Ocaml is the only language with the following feature:
-
Static type
-
Compile to native binary code
-
Powerful REPL
-
Strong FP support
Haskell is another one with these features, but it goes too far.
Nim is also a good candidate, however, without REPL.
Install
Install Ocaml, package manager Opam, and REPL utop with asdf:
asdf plugin-add ocaml
asdf list-all ocaml
asdf install ocaml 4.10.0 # takes a few minutes
asdf global ocaml 4.10.0
asdf plugin-add opam
asdf list-all opam
asdf install opam 2.0.6
asdf global opam 2.0.6
http_proxy=http://localhost:1080 https_proxy=http://localhost:1080 opam init
opam install utop # takes a few minutes
utop # utop is the ipython for python
Ref: Step-by-Step Guide to Manage OCaml Installations With asdf
Vim Integration
opam install merlin
opam user-setup install
Frequently Used Operations
Print function signiture
Input function name in utop, for example:
utop # List.filter;;
- : 'a list -> f:('a -> bool) -> 'a list = <fun>
Here utop #
is the prompt instead of codes written by user, the same below.
Read Files
Install Core with opam install core
and
add the following lines into ~/.ocamlinit:
#use "topfind";;
#thread
#require "core.top"
#require "core.syntax"
Read file contents with:
let res = Core.In_channel.read_all "filename.txt";;
String match
For example, test if str keyword in filelist:
utop # #require "core";;
utop # #require "str";;
utop # let filter_files (filelist: string list) (keyword: string): string list =
let str_in_file kw filename =
let lines = Core.In_channel.read_lines filename in
let kw_reg = Str.regexp (".*" ^ kw ^ ".*") in
let matched = List.filter lines (fun line -> Str.string_match kw_reg line 0) in
match List.length matched with
0 -> false
| _ -> true
in
List.filter filelist (fun afile -> str_in_file keyword afile);;
utop # let files = ["/home/leo/apps/dsnote/notes.sh"; "/home/leo/apps/dsnote/README.md"];;
utop # let res = filter_files files "power";;
val res : string list = ["/home/leo/apps/dsnote/README.md"]
Using 3rd Party Libraries
In REPL
To use a 3rd party library in REPL, for example "Core" here,
you should #require
it:
#require "core.top"
#require "core.syntax"
let res = Core.In_channel.read_all "filename.txt";;
#require
is a command of toplevel
, instead of a Ocaml function,
so it can't be used in source file.
Do NOT use open
, it will mess up the namespace.
For example, List.filter
and Core.List.filter
has different signatures.
If you open Core
in REPL while not in script file,
List.filter ...
will fail when compiled by ocamlopt
but pass in REPL.
Compile sources
Prefix the compilation command with ocamlfind
,
and add -package <pkg_name>
into the compilatin command:
cat << EOF > read_file.ml
let () =
let res = Core.In_channel.read_all Sys.argv.(1) in
print_endline res
EOF
ocamlbuild -pkgs core read_file.native
./read_file.native ~/.asdf/LICENSE
ocamlfind ocamlopt -o readfile -linkpkg -thread -package core read_file.ml
./readfile ~/.asdf/LICENSE
ocamlbuild
is prefered to ocamlfind
for cleaner syntax.
ocamlfind
can only find packages listed in ocamlfind list
.
Get the location of the package with ocamlfind query <pkg-name>
,
for example ocamlfind query core
.
Ref: