How to run ml/ocaml file without compiling?

How can I run my ocaml scripts without having to compile? Like in python I used to do:

python script.py

what I’ve done is this:

ocamlopt script.ml ; ./a.out

though that seems I cannot see the errors sometimes when I do that. Is there a better way?

1 Like

OCaml isn’t Python. For one thing, it is a compiled language, not an interpreted language. You can certainly find ways to package up the compilation process, but as with C or Rust or what have you, generally speaking, you need to compile first and then run your code. This has some disadvantages (you add a step to execution) but also some advantages (OCaml can be many orders of magnitude faster in execution.)

[Edited to add: I may be really wrong here, see @kit-ty-kate’s answer below.]

There is OCamlscript, but it doesn’t seem to be in good shape.

yes you can, like so:

ocaml script.ml

you’re gonna have to rely on topfind pragma if you want libraries but if you just need the standard library (i would advise for it), it works just fine as is.

7 Likes

I didn’t think that was particularly recommended. Is it?

why is it not recommend?

If Kate says it is, I’m probably wrong, but I’d like to hear a more detailed opinion…

I don’t think there’s any reason to recommend against trying code this way, particularly while learning the language. It’s similar to working in an interactive ocaml/utop session which is a perfectly reasonable approach.

7 Likes

What the others say about “Ocaml is a compiled language, and isn’t meant to be used for source-code-level scripting” is pretty much right. But like any other language with a reasonable toplevel, you can do it.

chet@twitter:~/tmp$ ./foo
argle
chet@twitter:~/tmp$ cat foo
#!/home/chet/Hack/Ocaml/4.07.1-ISMLGO/ocaml-base-compiler.4.07.1/bin/ocaml

let _ = print_string "argle\n"

Furthermore, there are serious packages, such as topkg that run as a script. We have an interpreter as part of OCaml, and there’s nothing wrong with taking advantage of it.

5 Likes

I have found that the final link stage of compilation can become a huge time sink relative to the compilation of touched files and found it beneficial to have a driver script load up libraries and launch without the linking of massive bytecode or native execs . Finished code can be packaged up as a compiled library leaving behind a smaller body of interpreted code going forward.
Not done this yet but on the wish-list is a way to move a bunch of files in and out of library status so as to maintain/extend it in the interpreter setting.

Another common use case is when you want to write a configure script in OCaml. Here is an example from dune.

I’m coming from Python and played a bit with a bit. As others noted you can just run a file like you would with Python,

ocaml script.ml

which IIUC byte compiles the file and then runs it. (just like Python in fact). You can also use the hash bang at the top of your script

#!/usr/bin/env ocaml 

and set the executable bit chmod +x script.ml.

I also timed this: byte compilation and execution is faster than Python so it still feels quick like a Python script.

4 Likes

Is it possible to do run my ocaml files with utop too (“like python”)?

Yes. From utop:

#use "myscript.ml";;
2 Likes

If you have a compelling need to do this, with a library that isn’t built into ocaml, you can build it into what’s in essence an extended ocaml interpreter. I’ve done that with the Unix library.

I would add that, you can also do:

utop scriptfile.ml

An additional tip! To use packages in “script files”, do:

#require "package-name";;
1 Like

what is the difference between #require vs #use?

From what I understand,

  • #require is utop specific, and loads installed libraries, and
  • #use loads .ml.

Someone please correct me if I’m wrong.

#require is ocamlfind specific it loads ocamlfind packages. utop integrates it by default but you can also use it in ocaml after a suitable #use "topfind":

> ocaml 
        OCaml version 4.12.0

# #use "topfind";;
- : unit = ()
Findlib has been successfully loaded. Additional directives:
  #require "package";;      to load a package
  #list;;                   to list the available packages
  #camlp4o;;                to load camlp4 (standard syntax)
  #camlp4r;;                to load camlp4 (revised syntax)
  #predicates "p,q,...";;   to set these predicates
  Topfind.reset();;         to force that packages will be reloaded
  #thread;;                 to enable threads

- : unit = ()
1 Like