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.
Related
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, ...
I have a program that uses the Bytes module from the Ocaml standard library and also opens the Core_kernel.Std module at the top of the file
open Core_kernel.Std
...
let let buf = Bytes.make bom_len '\x00' in
The problem I am having is that the latest version of Core_kernel introduced a new Bytes module that is shadowing the one from the standard library, which is resulting in a Unbound value Bytes.make compilation error.
Is there a way to solve this naming issue without getting rid of the open at the top of the file? If I did that it would require changing lots of things.
You could provide an alternative name for the Bytes module as such:
module B = Bytes
open Core_kernel.Std
let buf = B.make 10 '\x00'
and then do a search-replace in your code to change Bytes by B.
Another solution would be to avoid using open, but this would require a lot of changes in your code, I guess.
Core_kernel provides Caml module that binds everything that is available in standard library.
So, you could write this as
open Core_kernel.Std
...
let buf = Caml.Bytes.make bom_len '\x00' in
Unfortunately, Caml.Bytes is added only in 113.00.00 version that is not in OPAM yet.
I just realized that val big_endian : bool is removed from the Sys module when opening Core.Std.
Where can I find a similar value?
You can get access to vanilla OCaml Sys module using Caml module that includes the standard library:
let big_endian = Caml.Sys.big_endian
Anyway, it is really interesting, why they do not provided anything similar.
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.
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.