Greetings,
I’m having trouble compilling my program separated in 2 files. The idea is to make a small factory of Item, an abstract type defined in its module (Item).
item.ml:
module type Item =
sig
type item
val make_Item : int -> string -> string -> Item
end
module Item : ITEM =
struct
type Item = (int * string * string)
let make_item id name description = (id, name, description)
end
itemfactory.ml:
module type ItemFactory =
sig
val addItem : Item.item list -> int * string * string -> Item.item list
end
module ItemFactory : ItemFactory =
struct
let isIdValid id = id > 0
let addItem xs (id, name, description) =
if (isIdValid id) then
(Item.make_item id name description) :: xs
else
[]
end
Now, using the toplevel if I first #use “Item.ml” then #use “ItemFactory.ml”, it’ll work.
If I try to builld this manually, using make it won’t compile :
File "itemfactory.mli", line 4, characters 6-21:
4 | Item.item list ->
^^^^^^^^^^^^^^^
Error: Unbound type constructor Item.item
make: *** [Makefile:45 : item.cmi] Erreur 2
Since from what I think I’ve understood, the #use statement in toplevel just append everything in the “context”, I think my program can compile but I’m most likely missing a step ?
I tried to use “open Item” at the top of itemfactory.ml it still gives me the “Unbound type constructor…” error. Replacing open with include gives “Unbound MODULE type”.
Please let me know how I can get this to compile, and if what I’m doing is wrong let me know too! Thanks.
The ideal way to manage this would be to let the dune build system do it for you. See https://dune.build/
In your case you would just need to lay out your project directory with the following files:
dune
dune-project
item.ml
item_factory.ml
Note that you are redundantly wrapping each module, this is not needed because OCaml already treats each file as a module. So in item.ml you can just do:
(* item.ml *)
type t = int * string * string
let make id name description = id, name, description
And as a best practice you can put the interface in its own file:
(* item.mli *)
type t
val make : int -> string -> string -> t
And similarly for item_factory.ml.
Once this is done building the project would be as simple as dune build. And running it in the toplevel would be just: dune utop.
The error message mentions itemfactory.mli, but you didn’t mention this file in the description of the problem
As already suggested, one possibility is to use a higher-level build system like Dune. However, if you want to compile by hand, it shouldn’t be too difficult either:
Hello, thanks both of you for your answers.
So yes sorry I’ve omitted the fact that I provided mli interfaces for both modules.
I currently use Make to buid all my project/excercices, but I’ve tried to switch to dune today and it still doesn’t build. I already tried to build manually like you’ve expained with ocamlc -c and linking the cmos it can’t build itemfactory.mli so…
I haven’t changed the source (sorry I kept my abstract type as “item” and not “t” but I got what you’re trying to tell me), thanks for explaining the redundancy too, I wouldn’t know haha.
I just got rid of my Makefile and setup my directory to be exploitable(hopefully) by dune, using a lib folder as it has no entry point for now, so this is where I’m sitting at now, back to the very same problem:
user@linuxworkstation ~/Projetcs/Ocaml/item$ ls -lR
.:
total 8
-rw-r--r-- 1 user user 28 20 juin 14:49 dune-project
drwxr-xr-x 2 user user 4096 20 juin 15:02 lib
./lib:
total 20
-rw-r--r-- 1 user user 61 20 juin 14:50 dune
-rw-r--r-- 1 user user 453 20 juin 14:54 itemfactory.ml
-rw-r--r-- 1 user user 166 20 juin 14:53 itemfactory.mli
-rw-r--r-- 1 user user 307 20 juin 14:50 item.ml
-rw-r--r-- 1 user user 149 20 juin 14:53 item.mli
user@linuxworkstation~/Projetcs/Ocaml/item$ cat dune-project
(lang dune 2.7)
(name Item)
user@linuxworkstation~/Projects/Ocaml/agenda$ cat lib/dune
(library
(name Item_lib)
(modules item itemfactory))
user@linuxworkstation~/Projetcs/Ocaml/item$ dune build
File "lib/itemfactory.mli", line 4, characters 18-27:
4 | val addItem : Item.item list -> int * string * string -> Item.item list
^^^^^^^^^
Error: Unbound type constructor Item.item
user@linuxworkstation~/Projetcs/Ocaml/item$ dune build
File "lib/itemfactory.mli", line 4, characters 18-27:
4 | val addItem : Item.item list -> int * string * string -> Item.item list
^^^^^^^^^
Error: Unbound type constructor Item.itemuser@linuxworkstation ~/Projetcs/Ocaml/item$ ls -lR
.:
total 8
-rw-r--r-- 1 user user 28 20 juin 14:49 dune-project
drwxr-xr-x 2 user user 4096 20 juin 15:02 lib
./lib:
total 20
-rw-r--r-- 1 user user 61 20 juin 14:50 dune
-rw-r--r-- 1 user user 453 20 juin 14:54 itemfactory.ml
-rw-r--r-- 1 user user 166 20 juin 14:53 itemfactory.mli
-rw-r--r-- 1 user user 307 20 juin 14:50 item.ml
-rw-r--r-- 1 user user 149 20 juin 14:53 item.mli
user@linuxworkstation~/Projetcs/Ocaml/item$ cat dune-project
(lang dune 2.7)
(name Item)
user@linuxworkstation~/Projects/Ocaml/agenda$ cat lib/dune
(library
(name Item_lib)
(modules item itemfactory))
user@linuxworkstation~/Projetcs/Ocaml/item$ dune build
File "lib/itemfactory.mli", line 4, characters 18-27:
4 | val addItem : Item.item list -> int * string * string -> Item.item list
^^^^^^^^^
Error: Unbound type constructor Item.item
user@linuxworkstation~/Projetcs/Ocaml/item$ dune build
File "lib/itemfactory.mli", line 4, characters 18-27:
4 | val addItem : Item.item list -> int * string * string -> Item.item list
^^^^^^^^^
Error: Unbound type constructor Item.item
Here is item.mli:
module type ITEM =
sig
type item
val make_item : int -> string -> string -> item
end
module Item : ITEM
And itemfactory.mli:
module type ITEMFACTORY =
sig
val addItem : Item.item list -> int * string * string -> Item.item list
end
module Itemfactory : ITEMFACTORY
Just tried it works! Thanks so much!
I’m learning with a quite old ressources (2011 courses haha).
So I suppose this syntax (where you write module type etc) is not used anymore ? Or maybe for functors only ? I’ll finish this chapter and try to find recent ressources, thanks for your patience !
In addition you don’t need to specify modules, dune will find your modules automatically. That way when you add a new module, you don’t have to explicitly add it to your build file.
You can use that syntax if you want, it’s just that it’s redundant in this case. And then you end up with a nested module so you would have to write Item.Item.item to access the type. It’s much simpler to have just a single level of module in this case and have a type t so you just have to write Item.t.