Character constants: 'a'
List concatenation: l1 @ l2
String concatenation: str1 ^ str2
or String.cat str1 str2
Format string concatenation: str1 ^^ str2
Anonymous function: fun x y -> x + y
@@
: comparable to $
in haskell. First evaluates RHS then applies LHS to it. ʳ
'~Module.(e)~ is equivalent to let open Module in e
' ʳ
Check installed modules: ocamlfind list
Anonymous function: fun x -> 3
difference between = and ==:
==
: physical equality=
: structural equalityInteger division: /
Float division: /.
else if
, not elseif
Function arguments are eagerly evaluated.
Variables are made with let
.
Recursive functions are made with let rec
.
ocamlfmt
: an automatic code reformatter for ocaml
.mli
files: types for definitions in corresponding .ml file
.cmi
files: compiled form of .mli used during compilation?
Useful: https://doc.sherlocode.com/
More built-in modules:
3 2;;
# (=) bool = false
- :
3 3;;
# (=) bool = true - :
mem x l
: x ∈lhttps://ocaml.org/manual/5.2/api/List.html
Fun.flip
# Fun.flip;;fun>
- : ('a -> 'b -> 'c) -> 'b -> 'a -> 'c = <
List.mem;;
# list -> bool = <fun>
- : 'a -> 'a
List.mem;;
# Fun.flip list -> '_weak1 -> bool = <fun>
- : '_weak1
List.mem [2;3];;
# Fun.flip int -> bool = <fun>
- :
List.mem [2;3] 4;;
# Fun.flip bool = false
- :
List.mem [2;3] 3;;
# Fun.flip bool = true - :
Like Labeled arguments, but with a default value and ?
instead of a tilde.
>>> let foo ?(a=3) b = a + b;;
val foo : ?a:int -> int -> int = <fun>
>>> foo 2;;
- : int = 5
(* Overriding default value *)
>>> foo ~a:10 2;;
- : int = 12
(* Yeah, order doesn't matter *)
>>> foo 2 ~a:10;;
- : int = 12
>>> foo ~a:10;;
- : int -> int = <fun>
Reference: https://v2.ocaml.org/manual/lablexamples.html#s:optional-arguments
(|>)
operatorIt's like a reversed apply. ʳ
Function can be made to appear on RHS and its argument in LHS.
(|>);;fun>
- : 'a -> ('a -> 'b) -> 'b = <
0.0 |> sin;;
float = 0.
- :
sin 0.0;;
float = 0. - :
Useful to make a 'pipeline' where the value flows from the left to the right. As in:
let simple_process s =
Str.split Owl_nlp_utils.regexp_split sList.filter (fun x -> String.length x > 1)
|> String.concat " "
|> String.lowercase_ascii
|> Bytes.of_string |>
(forgot from where I got this snippet..)
We can make 'empty types'. ie, types without even a single constructor. ¹
Like:
type empty = |
Lack of constructors means it's impossible to construct a value of type empty
.
Via variance annotations.
+'a
-'a
By default, type variables are covariant.
ocaml infers them, but the explicit notation can be helpful in the 'interface' of modules (ocaml analogue of structures).
References:
Mutable values.
# incr;;
- : int ref -> unit = <fun>
# let r = ref 0;;
val r : int ref = {contents = 0}
# !r;;
- : int = 0
# incr r;;
- : unit = ()
# !r;;
- : int = 1
type person = {
string;
name: int
age: }
mutable
keyword in ocamlModifiable values. ie, non-pure.
mutable
is not part of the type. Just property of the variable.
type point = {
int;
x: mutable y: int
}
let p = {x=3; y=4};;
# val p : point = {x = 3; y = 4}
10
# p.x <- not mutable
Error: The record field x is
10;;
# p.y <- unit = ()
- :
# p3; y = 10} - : point = {x =
References:
They are labelled arguments.
let rec range ~first:a ~last:b =
if a > b then []
else a :: range ~first:(a+1) ~last:b
# rangeint -> last:int -> int list = <fun>
- : first:(* Show the argument labels! *)
3 5
# range int list = [3; 4; 5]
- :
(* Now argument order can be changed *)
10 ~first:3;;
# range ~last:int list = [3; 4; 5; 6; 7; 8; 9; 10] - :
Use within {|
and |}
.
# {| hello
world
|};;string = " hello\n world\n " - :
See: https://v2.ocaml.org/manual/patterns.html
Can use function
to pattern match without actually naming variables:
(* Given two lists, check if their concatenation is nil *)
let is2Nil = function
true
| [], [] -> false
| _, _ -> (* is2Nil : 'a list * 'b list -> bool *)
Or can use match
as in Coq:
let is2Nil a b =
match a, b with
true
| [], [] -> false | _, _ ->
https://ocaml.org/manual/5.2/api/Array.html
arr.(i)
/ get arr i
arr.(i).(j)
arr.(i) <- new_val
set arr i new_val
length arr
let a = [|1; 2; 3; 4|];;
# val a : int array = [|1; 2; 3; 4|]
Analogues:
sml | ocaml | comment |
---|---|---|
structure | module | |
signature | module type | |
fn | fun | Anonymous functions |
f o g | -NA- | Function composition |
case | match | Pattern matching |
Apparently, ocaml doesn't have a built-in compose
function.
—
List elements are separated with ;
in ocaml and ,
in sml
sml:
of New Jersey (64-bit) v110.95 [built: Sat Feb 05 19:22:43 2022]
Standard ML 1,2,3];;
[val it = [1,2,3] : int list
OCaml:
4.14.1
OCaml version for help.
Enter #help;;
1,2,3];;
[int * int * int) list = [(1, 2, 3)]
- : (
1;2;3];;
[int list = [1; 2; 3] - :
See: http://adam.chlipala.net/mlcomp/
From https://ocaml.org/docs/objects:
OCaml is an object-oriented, imperative, functional programming language. It mixes all these paradigms and lets you use the most appropriate (or most familiar) programming paradigm for the task at hand.
(Haskell is 'purer' than OCaml in the sense that there is lesser chance of side-effects.)
ocaml supports OOP-style classes: https://ocaml.org/docs/objects
foo
of an object obj
with obj#foo
new
keyword is used to make a new object of a class
new LTerm_widget.hbox
https://ocaml.org/docs/if-statements-and-loops
for
and while
loops available.break
, continue
Links:
[@@deriving _]
An automatic code formatter.
dune integration (needs setup in dune-project):
Dry run: dune build @fmt
Apply: dune promote
Ignore all warnings: dune <command> –profile release
# Initialize new project
dune init proj <proj-name>
dune build
dune exec
References: https://ocaml.org/docs/up-and-running
Both of the following are equivalent??
dune exec -- <cmd>
dune install; <cmd>
opam switches are comparable to python's venvs: https://ocaml.org/docs/opam-switch-introduction
Show switches available to be installed: opam switch list-available
Activate: eval $(opam env)
Create new switch: opam switch create <switch-name>
opam switch create 5.1.1
Delete a switch: opam switch remove <switch-name>
default
??List switches: opam switch
Go to a switch: opam switch <switch-name>
List installed packages: opam list
or opam list -i
Change switch: opam switch set <switch-name>
Install a package (to current switch): opam install <package-name>
Remove a package: opam remove <package-name>
Update package list: opam update
Many useful packages are available only after adding this repo: opam repo add coq-released https://coq.inria.fr/opam/released
Reference: https://opam.ocaml.org/doc/Usage.html
Can work with utop.
M-x run-ocaml
: start tuareg (is an alias for tuareg-run-ocaml
)C-c C-s
: Start utopC-x C-e
/ C-c C-e
: Feed block of current line (or selection) to utopC-c C-t
: Show type of value under cursorhttps://ocamlpro.github.io/ocaml-cheat-sheets/tuareg-mode.pdf
Tuareg: Emacs major mode for OCaml.
Insert template code snippet:
let _ in
if _ then _ else _
match _ with _
https://www.systutorials.com/utop-key-bindings-key-shortcuts/
Jane Street libraries:
Historical:
base is a package from janestreet.
# #use "topfind";;
# #require "base";;
# open Base;;
base < corekernel < core
The extra #
are needed.
.mli
filesEnclose the operator within parenthesis.
Example:
List.map (fun s -> "prefix " ^ s) l;;
utop # string list = ["prefix hi"; "prefix hello"]
- :
List.map ((^) "prefix ") l;;
utop # string list = ["prefix hi"; "prefix hello"]
- :
List.map (String.cat "prefix ") l;;
utop # string list = ["prefix hi"; "prefix hello"]
- :
utop # (^) ;;string -> string -> string = <fun>
- :
"a";;
utop # (^) string -> string = <fun> - :
Just put the name consisting of special characters and enclose it within parenthesis, I guess. https://stackoverflow.com/questions/38147841/how-to-define-an-infix-not-symbolic-aka-not-an-operator-function-in-ocaml
utop # let (+-) x y = x + y;;
val ( +- ) : int -> int -> int = <fun>
utop # 3 +- 4;;
- : int = 7
utop # let (a) x y = x + y;;
Error: Syntax error
if
without else
This is possible if the then
part value is of type unit
.
fun x -> if x<3 then () ;;
int -> unit = <fun> - :
Otherwise, it would give error:
fun x -> if x<3 then "hi" ;;
# type string but an expression was expected of type
Error: This expression has unit
in the result of a conditional with no else branch because it is
Links:
This is a function:
let gethm () =
let now = Unix.localtime (Unix.time ()) in
let hour = now.tm_hour in
let minute = now.tm_min in
(hour, minute)
But this is a value:
let gethm =
let now = Unix.localtime (Unix.time ()) in
let hour = now.tm_hour in
let minute = now.tm_min in
(hour, minute)
No primitives for concurrency till Ocaml5.
Can think of effect handlers as 'first-class, restartable exceptions'
(* When [E] is performed, we will get a value of type [string] *)
string
effect E:
(* A computation. Like a thunk *)
let comp () =
print_string "0: start";
print_string (perform E);
print_string "3: end";
let main () =
try
comp ()(* Effect handler. [k] is a delimited continuation *)
with effect E k ->
print_string "1: EH start";
"2: EH cont";
continue k print_string "4: EH end";
Here control goes like:
#load
Error: Reference to undefined global `Unix' Hint: This means that the interface of a module is loaded, but its implementation is not. Found home/famubu.opam/5.1.0/lib/ocaml/unix/unix.cma in the load paths. Did you mean to load it using #load "unix.cma" or by passing it as an argument to the toplevel?
let now = Unix.localtime (Unix.time ()) in let hour = now.tmhour in let minute = now.tmmin in (hour, minute);;
val gethm : int * int = (11, 25)
#+endsrc
dune exec clock
$ 2024-08-19 09:08:43.72231Z ERROR [thread=3] Process <0.5.0> died with unhandled exception Invalid_argument("index out of bounds"):
OCAMLRUNPARAM=b
$
dune exec clock
$ 2024-08-19 09:09:35.34246Z ERROR [thread=0] Process <0.6.0> died with unhandled exception Invalid_argument("index out of bounds"):
Raised by primitive operation at Clock__Model.build_outstr in file "lib/model.ml", line 112, characters 8-24
Called from Minttea__Program.init in file "minttea/program.ml", line 49, characters 13-35
Called from Runtime__Import._spawn.(fun) in file "riot/runtime/import.ml", line 92, characters 10-15
Another example:
export OCAMLRUNPARAM=b
$ dune exec clock
$ 2024-08-19 09:11:36.12397Z ERROR [thread=2] Process <0.6.0> died with unhandled exception Invalid_argument("index out of bounds"):
Raised by primitive operation at Clock__Model.build_outstr in file "lib/model.ml", line 79, characters 8-22
Called from Minttea__Program.init in file "minttea/program.ml", line 49, characters 13-35
Called from Runtime__Import._spawn.(fun) in file "riot/runtime/import.ml", line 92, characters 10-15
Meant to supercede an older tool?: ocamldoc
Cross referencing possible
Use comments in the (** ‥ *)
format.
Module docstring: First odoc comment
Type, exception docstrings: odoc comment right before definition (normal comments can be there in between though)
Constructor docstring: On same line
Function docstring: before and after function definition
Stop odoc mode with a 'stop comment': (**/**)
Inlince code: [hello]
List: ul, ol
Alignment:
Blocks
Man page 'flags' provided by Cmdliner:
`S | section |
`P | paragraph |
`I | label-text paragraph |
`Pre | pre-formatted text |
`Noblank | suppress blank line between 2 blocks |
`Blocks | list of (more) blocks |
From https://erratique.ch/software/cmdliner/doc/Cmdliner/Manpage/index.html
'Markup'
$(i, text)
$(b, text)
https://erratique.ch/software/cmdliner/doc/tool_man.html#doclang
–
$(tname)
: term name (ie, command name?)$(mname)
: main command name$(iname)
https://erratique.ch/software/cmdliner/doc/Cmdliner/Cmd/index.html#info
–
eval_ok
: type for successful evaluationeval_error
: type for unsuccessful evaluationhttps://erratique.ch/software/cmdliner/doc/Cmdliner/Cmd/index.html#eval_low
Term
const value
: a Term
that evaluates to value
($)
/ app
: function application with respect to Term
Evaluate Term
to get Result
, which can be used to get an exit status.
Env
Term.env_info
val info: ?deprecated:string -> ?docs:string -> ?doc:string -> var -> info
Cmd
val v : info -> 'a Term.t -> 'a t
v i t
is a command with information i and command line syntax parsed by Cmd.t
.Hardcaml.Rtl
: https://github.com/janestreet/hardcaml/blob/master/docs/rtl_generation.mdOperations
https://github.com/janestreet/hardcaml/blob/master/docs/combinational_logic.md
(+:)
: addition(-:)
: subtraction(*:)
: unsigned multiplication(*+)
: signed multiplication(&:)
: logical and(|:)
: logical or(^:)
: logical xor(
:)~: logical notVectors:
select v ~high:3 ~low:2
or v.:[3,2]
v1 @ v2