"Unbound type constructor _no_unused_value_warning" (only when #use ing file) - ocaml

Consider this very basic module definition:
module type My_test = sig
type config with sexp
end;;
When I directly enter this on the utop prompt, everything works fine:
utop # module type My_test = sig
type config with sexp
end;;
module type My_test =
sig type config val config_of_sexp : Sexp.t -> config val sexp_of_config : config -> Sexp.t end
But when I try to #use a file containing the exact same definition, I get an Unbound type constructor _no_unused_value_warning_ error:
utop # #use "dummy.mli";;
File "dummy.mli", line 2, characters 7-13:
Error: Unbound type constructor _no_unused_value_warning_
(line 2 is type config with sexp )
Version info: The universal toplevel for OCaml, version 1.7, compiled for OCaml version 4.01.0
UPDATE:
I'm starting a bounty since I'd really be interested in
knowing whether this is an OCaml bug
sensible workarounds / fixes for my code

1) The ocaml top-level has two undocumented options named: -dsource & -dparsetree
2) If I enable the -dsource and then try the #use "dummy.mli". I saw that the source that was generated looked like this:
$ ocaml -dsource
# #use "dummy.mli";;
module type My_test =
sig
type config
val config_of_sexp : (Sexplib.Sexp.t -> config) _no_unused_value_warning_
val sexp_of_config : (config -> Sexplib.Sexp.t) _no_unused_value_warning_
end;;
File "dummy.mli", line 1, characters 31-37:
Error: Unbound type constructor _no_unused_value_warning_
3) however, when I directly enter the type declaration directly into the toplevel the source generated did not have the "_no_unused_value_warning_"
4) The parse-tree that is generated for these two cases is slightly different, due to the presence of _no_unused_value_warning_.
5) After some greping I saw that the type_conv library inserts `'val name : _no_unused_value_warning_' as a sort of hack to deactivate warnings -- https://github.com/janestreet/type_conv/blob/master/lib/pa_type_conv.ml -- there is a comment starting on line 916 that explains this stuff (I am still learning ocaml, so I don't yet understand everything about these parts)
Since sexplib uses type_conv, this signature was added in this case.
6) But, the real issue here has to be be how the ocaml toplevel handles the #use directive and the directly input lines of code.
In this file: https://github.com/diml/ocaml-3.12.1-print/blob/master/toplevel/opttoploop.ml
-- use_file (at line 316) uses List.iter to loop over a list of Parsetree.toplevel_phrase and calls execute_phrase on each element.
The REPL loop (at line 427) calls execute_phrase on a single Parsetree.toplevel_phrase
7) I am still not sure what is really causing the difference in the parse-tree - but trying to figure it out was interesting.
It would be awesome if someone who understands these parts more posted an answer.

I ran into this today using utop 1.17 with Ocaml 4.02.1. After reading gautamc'e excellent answer, I tried this simple workaround:
utop # type 'a _no_unused_value_warning_ = 'a;;
This allowed me to successfully #use the module I had been having a problem with.

Related

Base deprecates some useful functions

I am used to using the standard function print_int in OCaml, but when I open the library Base by Jane Street, as recommended in the book Real World OCaml, I obtain a deprecation warning:
utop # print_int;;
- : int -> unit = <fun>
utop # open Base;;
utop # print_int;;
Line 1, characters 0-9:
Alert deprecated: Base.print_int
- : int -> unit = <fun>
Even worse, when I build it with dune, as recommended in that book, warnings become errors. What should I do ? Replace print_int with printf "%i" ? or with Caml.print_int ? Both seem to work but look needlessly complicated. Something else ?
Thank you.
This is answered here: https://ocaml.janestreet.com/ocaml-core/v0.13/doc/base/index.html#using-the-ocaml-standard-library-with-base
Base is intended as a full stdlib replacement. As a result, after an open Base, all the modules, values, types, etc., coming from the OCaml standard library that one normally gets in the default environment are deprecated.
In order to access these values, one must use the Caml library, which re-exports them all through the toplevel name Caml: Caml.String, Caml.print_string, ...

Complaining about with default in OCaml

The following code from Real World OCaml Chapter 17: Data Serialization with S-Expressions page 339 is not compiling on utop:
type http_server_config = { web_root: string;
port: int with default(80);
addr: string with default("localhost");
} [##deriving sexp] ;;
It is complaining about the with in port: int with default(80);
Thanks!
In recent versions of the Janestreet's Core library, all syntax extensions have been converted from camlp4 extensions to ppx extensions. Consequently, you unfortunately need to adapt the syntax of all examples using syntax extensions in Real World OCaml.
Fortunately, contrarily to camlp4 extensions, ppx extensions cannot wildly modify OCaml syntax. At most they can use a slightly extended syntax compared to vanilla OCaml, wich adds extension nodes and attributes.
In particular, this means that since field:type with … is not synctatically valid for vanilla OCaml, it is also not a valid syntax with the ppx_sexp_conv extension enabled. In your case, the default value annotation needs to be written as an attribute of the corresponding record fields:
type http_server_config = {
web_root: string;
port: int [#default 80];
addr: string [#default "localhost"];
} [##deriving sexp] ;;
Note that in order to work in utop you need first to have required the
ppx_sexp_conv extension and opened the default runtime module:
#require "ppx_sexp_conv";;
open Sexplib.Std ;;
type http_server_config = {
web_root: string;
port: int [#default 80];
addr: string [#default "localhost"];
} [##deriving sexp] ;;
The examples in Real World OCaml assume you have Core installed, which includes some syntax extensions. I followed the installation instructions here and I still see the same problem you're seeing.
When I tried to install the syntax extending module, I saw this:
utop # #camlp4o;;
utop was built without camlp4 support.
So, I conclude that it's a little bit tricky to set up the environment that Real World OCaml is expecting.
At any rate, #Basile_Starynkevitch is correct. The code is using syntax extensions that aren't supported in your utop.

Programmatically load code in sml/nj

I try to load an external .sml file - let's say a.sml - and execute a fun (add: int -> int -> int) listed in this file.
I perfectly know how to do this in the interactive shell: use "a.sml";
But how to achieve this in a .sml file? I tried the following:
val doTest =
let
val _ = print ("Loading..." ^ "\n")
val _ = use "a.sml"
val _ = print ("1 + 2 = " ^ Int.toString (add 1 2) ^ "\n")
in
1
end
But the compilers reaction is:
test.sml:7.49-7.52 Error: unbound variable or constructor: add
BTW: I know that using the CM is the more appropriate way. But in my case I do not know the file a.sml prior to the compilation.
You can't do this. The compiler must know the types of the functions you are calling at compile time. What you are asking is for SML to load a file at run time (use ...) and subsequently run the code therein. This isn't possible due to the phase distinction; type checking occurs during compilation, after which all type information can be forgotten.
If you're generating code and know the file name, you can still use the CM and compile in two steps using your build system. Then you'd get the type errors from the generated code in the second compilation step. Please describe your situation if such an approach doesn't work for you.

Datalog require field `unlock'

While compiling an OCaml application I get the following error:
File "/tmp/ocamlpp466ee0", line 308, characters 34-233:
Error: Signature mismatch:
...
The field `unlock' is required but not provided
The field `lock' is required but not provided
Command exited with code 2.
My guess is that the error is releated with the OCaml library Datalog (I've installed the version 0.3 from here) because the line 308 in the file is /tmp/ocamlpp466ee0 the first one in the following code
module Logic = Datalog.Logic.Make(struct
type t = atom
let equal = eq_atom
let hash = hash_atom
let to_string a = Utils.sprintf "%a" pp_atom a
let of_string s = atom_of_json (Json.from_string s)
end)
I would really appreciate if someone could help me to know what I am doing wrong.
Moreover, I would like to undestand why the file /tmp/ocamlpp466ee0 is generated each time I execute 'make'? I tried to understand by reading the Makefile but I did not succeed.
I think that something have changed in Datalog library and in some version > 0.3 functor Datalog.Logic.Make requires module argument with values lock and unlock declared. So, it's version problem.
About temporary file. As you can see, its name consists of ocaml literal, pp which means preprocessor and some number. Preprocessors in OCaml usually work this way: they read input source file and write output source files. That's why some temporary files are created.

SML-NJ, how to compile standalone executable

I start to learn Standard ML, and now I try to use Standard ML of New Jersey compiler.
Now I can use interactive loop, but how I can compile source file to standalone executable?
In C, for example, one can just write
$ gcc hello_world.c -o helloworld
and then run helloworld binary.
I read documentation for SML NJ Compilation Manager, but it don`t have any clear examples.
Also, is there another SML compiler (which allow standalone binary creating) available?
Both MosML and MLton also have the posibility to create standalone binary files. MosML through mosmlc command and MLton through the mlton command.
Note that MLton doesn't have an interactive loop but is a whole-program optimising compiler. Which in basic means that it takes quite some time to compile but in turn it generates incredibly fast SML programs.
For SML/NJ you can use the CM.mk_standalone function, but this is not advised in the CM User Manual page 45. Instead they recommend that you use the ml-build command. This will generate a SML/NJ heap image. The heap image must be run with the #SMLload parameter, or you can use the heap2exec program, granted that you have a supported system. If you don't then I would suggest that you use MLton instead.
The following can be used to generate a valid SML/NJ heap image:
test.cm:
Group is
test.sml
$/basis.cm
test.sml:
structure Test =
struct
fun main (prog_name, args) =
let
val _ = print ("Program name: " ^ prog_name ^ "\n")
val _ = print "Arguments:\n"
val _ = map (fn s => print ("\t" ^ s ^ "\n")) args
in
1
end
end
And to generate the heap image you can use: ml-build test.cm Test.main test-image and then run it by sml #SMLload test-image.XXXXX arg1 arg2 "this is one argument" where XXXXX is your architecture.
If you decide to MLton at some point, then you don't need to have any main function. It evaluates everything at toplevel, so you can create a main function and have it called by something like this:
fun main () = print "this is the main function\n"
val foo = 4
val _ = print ((Int.toString 4) ^ "\n")
val _ = main ()
Then you can compile it by mlton foo.sml which will produce an executable named "foo". When you run it, it will produce this as result:
./foo
4
this is the main function
Note that this is only one file, when you have multiple files you will either need to use MLB (ML Basis files) which is MLtons project files or you can use cm files and then compile it by mlton projectr.mlb