Syntax error when using batteries in Utop - ocaml

I've successfully installed Batteries and can get it work...somewhat.
Any ideas why I'm getting the syntax error since Opam list this:
depends: "ocaml" {>= "4.00.0" & < "4.10.0"}
And, I'm at: The OCaml toplevel, version 4.07.1

This code relies on camlp4 preprocessor which is deprecated and is no longer supported. Moreover, list comprehension is no longer a part of the Batteries library and is a separate package. So you need to install it using opam install pa_comprehension. You can still make your code work for OCaml 4.07.1, by issuing the following directives right after you start OCaml toplevel (or utop)
#use "topfind";;
#camlp4o;;
#require "pa_comprehension";;
The first directive (note you have to type # it is a part of the directive), enables ocamlfind in the toplevel (I think it is not needed in utop, but won't hirt). The next directive enables camlp4o syntax, so that all inputs are preprocessed. You're no longer coding in OCaml after that, but in camlp4o dialect. Finally, the last directive loads the preprocessor that supports list comprehensions.
To compile the code that uses list comprehension you need to specify the same options to the compiler (i.e., enable syntax, load the preprocessor), e.g.,
ocamlfind ocamlopt -syntax camlp4o -package pa_comprehension -linkpkg example.ml -o example
The camlp4 package also provides another list comprehension syntax, which is a little bit different from the one that is provided by Batteries. It is called camlp4.listcomprehension, and you can use it with roughly the same invocations modulo the package name, e.g., in toplevel,
#use "topfind";;
#camlp4o;;
#require "camlp4.listcomprehension";;
and to compile
ocamlfind ocamlopt -syntax camlp4o -package camlp4.listcomprehension -linkpkg example.ml -o example
With all that said, I highly discourage you from using camlp4 list comprehension in modern days. This is an obsolete technology.
Besides, your example is ill-formed, you're missing the ? character in the closing bracket, e.g., this is an example interaction with the toplevel,
# #use "topfind";;
# #camlp4o;;
# #require "pa_comprehension";;
# open Batteries;;
# [? x | x <- 1--10; x mod 2 = 0 ?];;
- : int Batteries.Enum.t = <abstr>

Related

use packages installed with opam inside utop

I installed yojson with opam:
opam install yojson
and I want to use it inside utop, but I haven't been able to make it work. I've tried these commands inside utop and none of them worked (it complains that it can't find the file / package):
#use "Yojson";;
#use "yojson";;
#require "Yojson";;
#require "yojson";;
Is there any additional configuration I should be aware of to use opam packages in utop?
The correct invocation is (include the # character):
#use "topfind";;
#require "yojson";;
The first command enables the #require directive (it is not the standard one, but comes from the ocamlfind tool), it is a good idea to add it to your ~/.ocamlinit file, if it is not there already. The second directive, actually loads the yojson library. You can also use the #list directive to list all available packages, as well as the ocamlfind list shell command for the same puprose.

Is it possible to compile OCaml codes using Core without corebuild?

I'm using Ubuntu 18.04. I have OCaml 4.05 installed (via apt-get) as well as utop and Core (via opam). And this is the content of my ~/.ocamlinit:
(* Added by OPAM. *)
let () =
try Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH")
with Not_found -> ()
;;
#use "topfind";;
#thread;;
#camlp4o;;
#require "core.top";;
#require "core.syntax";;
Compiling OCaml codes which use Core works fine with corebuild. It doesn't work with plain ocamlc or ocamlopt though. They complain:
Error: Unbound module Core
And I found corebuild to be pretty picky. It doesn't like any existing non-OCaml codes in the same directory:
SANITIZE: a total of 12 files that should probably not be in your source tree
has been found. A script shell file "/home/anta40/Codes/_build/sanitize.sh"
is being created. Check this script and run it to remove unwanted files or
use other options (such as defining hygiene exceptions or using the
-no-hygiene option).
IMPORTANT: I cannot work with leftover compiled files.
ERROR: Leftover object files:
File hellod.o in . has suffix .o
File helloscheme_.o in . has suffix .o
File nqueens.o in . has suffix .o
File helloscheme.o in . has suffix .o
File HelloHS.o in . has suffix .o
File helloml.o in . has suffix .o
ERROR: Leftover OCaml compilation files:
File nqueens.cmo in . has suffix .cmo
File helloml.cmo in . has suffix .cmo
File helloml.cmi in . has suffix .cmi
File nqueens.cmi in . has suffix .cmi
File nqueens.cmx in . has suffix .cmx
File helloml.cmx in . has suffix .cmx
Exiting due to hygiene violations.
Compilation unsuccessful after building 0 targets (0 cached) in 00:00:00.
Using the -no-hygiene option, e.g corebuild sum.ml -no-hygiene doesn't produce any native executable. Is there any workaround?
`
The OPAM package manager can support multiple OCaml instances, where each groups an OCaml installation (ocaml, ocamlc, ocamlopt, etc.) with installed packages. Each instance is called a switch.
Type ocaml switch to see a list of instances. In terms of switches, the installation of OCaml using packages (apt-get) is called system.
It may be better to avoid mixing the system and OPAM installations. I suggest that you create a new switch, ensure that the OPAM settings are properly sourced, and install Core into it the new switch :
opam switch 4.06.1
eval $(opam config env)
opam install core
The automatic build tools assume that they control the entire build process and complain when they find other compilation results. Normally, running the suggested shell script and retrying side-steps the problem, even if only to uncover another one. Your second problem (with -no-hygeine) may be related to the installation issues.
Your installation is dated.
I imagine that you followed instructions in Real World OCaml but OCaml ecosystem has moved since the first edition of RWO. To get a modern installation you should follow the dev version of Real World OCaml https://dev.realworldocaml.org/install.html .
To answer your question, corebuild is a fine wrapper around ocamlbuild. To build an executable from a sum.ml with corebuild, you should use
corebuild sum.native
for native executable or
corebuild sum.byte
for bytecode compilation
Otherwise, you can invoke ocamlopt through ocamlfind:
ocamlfind ocamlopt -package core sum.ml
Finally, if you intend to build larger project, you ought to have a look to dune https://jbuilder.readthedocs.io/en/latest/overview.html .

Use ocamlfind with ocaml interpreter, without compiling

I have a file main.ml that uses some package that makes the command ocaml main.ml fail and report this error:
Error: Unbound module X
And the only solution I've found so far is to run:
ocamlbuild main.native -use-ocamlfind -package X
./main.native
But this compiles the file. Is there a way to just run the regular ocaml interpreter (ocaml main.ml) with some additional flags to make it find the package?
The easiest way is probably to use topfind and add #require "core" at the top of your file. If you want to avoid adding toplevel directives in your file, you can use ocamlfind query -i-format -r to compute the required include directories:
ocaml $(ocamlfind query -i-format -r core) main.ml
You can put at the beginning of your file some top-level directives which find and load needed modules. For example, when I want to use Core library in my script I insert:
#use "topfind";;
#thread;;
#require "core";;
open Core.Std
(* Code of my script *)
To use topfind package ocamlfind has to be installed (opam install ocamlfind)
You can also query the path of your package to ocamlfind :
ocamlfind query package_X
That will return the path of your package : /path_to/packageX
And then :
ocaml main.ml -I /path_to/packageX

Loading a batteries dependent file into ocamltop -- the interfaces disagree

Here is a simple ocaml file, just meant to get me to understand how to load a program that uses the Batteries library into the ocamltop.
batteryassault.ml
open Batteries
let main = print_string "hello, world ... powered on"
I compile this to bytecode with
ocamlfind ocamlc -package batteries -linkpkg batteryassault.ml
Resulting in batteryassault.cmo and batteryassault.cmi, and no errors nor warnings. Then, I start the battery-powered ocamltop with
rlwrap ocamlfind batteries/ocaml
Finally, to load the file in ocamltop:
#load "batteryassault.cmo" ;;
And then we get an error.
The files batteryassault.cmo and /usr/lib/ocaml/batteries/batteries.cma
disagree over interface Batteries
I think what could be going on is that Ubuntu installs batteries 2.2.1, but for some reason (installing merlin?) I have batteries 2.3.1 installed in my opam folder, and moreover, when starting the ocamltop with batteries as above, it indicates that ocamltop is using the 2.2.1 version. Further, compiling with
ocamlfind ocamlc -package batteries -linkpkg batteryassault.ml -verbose
I find that ocamlc is definitely using the library in opam, i.e. the 2.3.1 version.
So my question is: what is the/is there a workaround?
Usually I suggest to remove system OCaml installation at all. Otherwise you may have such errors.
You should ensure, that all your tools and libraries come from the same source, in this particular case from opam.
A usual error is to forget to call for
eval `opam config env`
at some point. You may recall later about this, and activate your opam, thus ending up, with parts of your application, or even opam stack built using opam with other parts built with system libraries. If you made such error, it will be hard to guess, when and what goes wrong.
But if you still don't want to remove system batteries, then you need to be very careful. For example, since ocamlfind batteries/ocaml results in loading old version of batteries, then you can try to use this trick, to make sure that batteries topleve is loaded from opam:
$ `opam config var batteries:lib`/ocaml
If the problem persists, that means that your system is really broken. Consider removing you opam stack and making carefully everything from scratch. E.g.,
rm -rf ~/.opam
opam init --comp=4.02.1
eval `opam config env`
opam install batteries

OCaml: How to Run a Script with Libraries Included

I'm following the Real World OCaml book to learn OCaml and many of the programs require using the Jane Street Core library. When I use functions from this core library in the toplevel, it works great. There, I just use the following commands to open the Core library.
$ #use "topfind";;
#thread;;
#camlp4o;;
#require "core.top";;
#require "core.syntax";;
open Core.Std;;
Then I can run this program line by line in the toplevel and functions like String.split work fine.
# let languages = "OCaml,Perl,C++,C";;
val languages : string = "OCaml,Perl,C++,C"
# let dashed_languages =
let language_list = String.split languages ~on:',' in
String.concat ~sep:"-" language_list
;;
val dashed_languages : string = "OCaml-Perl-C++-C"
But if I put it all in a script, how do I make the compiler recognize the core libraries? So if I'm running the same program in a script:
open Core.Std;;
open Str;;
let languages = "OCaml,Perl,C++,C";;
let dashed_languages =
let language_list = String.split languages ~on:',' in
String.concat ~sep:"-" language_list
;;
Then I compile it:
ocamlopt -o test test.ml
I get an error:
Error: Unbound module Core
So clearly Core is not being recognized. I can't put the #use and #require commands in my script because OCaml doesn't recognize those. So how can I use Core?
Since you're following Real World OCaml, you may want to use corebuild to compile executables since this is what the book recommends. In this case the command corebuild test.native should correctly compile your script. If you use libraries other than Core, you'll need to specify them with the -pkg option.
Also, note you can omit the double semicolons within a .ml file.
Make sure you have ocamlfind. Also, make sure you have the right environment for it to find packages. If you installed with opam, run "eval opam config env". Then:
ocamlfind ocamlopt -linkpkg -thread -package core test.ml -o test