This page gives a quick side by side comparison of program fragments in the
two ML dialects Standard ML
('97 revision) and Objective
Caml (version 3.12). It is primarily targetted at people who need to convert
code between the two dialects. Where suitable we also mention common extensions
to SML, or recent extensions of Ocaml. The comparison does not cover features
that do not have an appropriate counter part in the sibling dialect (e.g.
Ocaml's object sublanguage, SML's user-defined operator fixity, or advanced
library issues).
The first section is an interaction with the respective toplevel system, in
order to show the built-in types. The rest just consists of example expressions
and definitions. Keywords and other reserved symbols are
type-set in blue.
SML |
Ocaml |
- 3;
> val it = 3 : int
|
# 3;;
- : int = 3
|
- 3.141;
> val it = 3.141 : real
|
# 3.141;;
- : float = 3.141
|
- "Hello world";
> val it = "Hello world" : string
|
# "Hello world";;
- : string = "Hello world"
|
- #"J";
> val it = #"J" : char
|
# 'J';;
- : char = 'J'
|
- true;
> val it = true : bool
|
# true;;
- : bool = true
|
- ();
> val it = () : unit
|
# ();;
- : unit = ()
|
- (3, true, "hi");
> val it = (3, true, "hi") : int * bool * string
|
# (3, true, "hi");;
- : int * bool * string = 3, true, "hi"
|
- [1, 2, 3];
> val it = [1, 2, 3] : int list
|
# [1; 2; 3];;
- : int list = [1; 2; 3]
|
- #[1, 2, 3];
> val it = #[1, 2, 3] : int vector
Standard does not have vector literals but most implementations
support them – use library functions otherwise
|
Does not have vectors – use arrays
|
Does not have array literals – use library functions
|
# [|1; 2; 3|];;
- : int array = [|1; 2; 3|]
|
SML |
Ocaml |
fn f =>
fn x =>
fn y => f(x,y)
|
fun f ->
fun x ->
fun y -> f (x,y)
or
fun f x y ->
f (x,y)
|
fn 0 => 0
| n => 1
|
function 0 -> 0
| n
-> 1
|
f o g
|
fun x -> f (g x)
|
map SOME xs
|
Does not have first-class constructors – use function instead, e.g.
map (fun x
-> Some x) xs
|
map #2 triples
map #lab records
|
Does not have first-class selectors – use function instead, e.g.
map (fun
(_,x,_)
-> x) triples
map (fun x
-> x.lab) records
|
f (inputLine stdIn) (inputLine stdIn)
|
Evaluation order is undefined for application – use let , e.g.
let line1 = read_line ()
in
let line2 = read_line ()
in
f line1 line2
|
SML |
Ocaml |
if 3 > 2 then "X"
else "Y"
|
if 3 > 2 then "X"
else "Y"
|
if 3 > 2
then print "hello"
else ()
|
if 3 > 2
then print_string "hello"
Note: expression has to have type unit
|
while true do
print "X"
|
while true do
print_string "X"
done
|
Does not have for loops –
use recursion or while
|
for i = 1
to 10
do
print_endline "Hello"
done
|
(print "Hello ";
print "world")
|
print_string "Hello ";
print_string "world"
or
(print_string "Hello ";
print_string "world")
or
begin
print_string "Hello ";
print_string "world"
end
|
SML |
Ocaml |
type t =
int -> bool
|
type t =
int -> bool
|
type ('a,'b) assoc_list
=
('a * 'b) list
|
type ('a,'b) assoc_list
=
('a * 'b) list
|
datatype 'a option =
NONE |
SOME of 'a
|
type 'a option =
None |
Some of 'a
|
datatype t =
A of int
| B of u
withtype u =
t * t
|
type t =
A of int
| B of u
and u =
t * t
|
datatype v =
datatype t
|
type v =
t =
A of int
| B of u
|
datatype complex = C of real * real
fun complex xy = C xy
fun coord (C xy) = xy
|
type complex = C of float * float
let complex (x,y) = C (x,y)
let coord (C (x,y)) = (x,y)
or (note parentheses in type declaration)
type complex = C of (float * float)
let complex xy = C xy
let coord (C xy) = xy
|
SML |
Ocaml |
fun getOpt(NONE, d) =
d
| getOpt(SOME x,
_) = x
|
let get_opt =
function
(None, d) -> d
| (Some x,
_) -> x
|
fun getOpt (opt, d) =
case opt
of
NONE =>
d
| SOME x
=> x
|
let get_opt (opt, d) =
match opt
with
None -> d
| Some x
-> x
|
fun take 0 xs =
[]
| take n nil =
raise Empty
| take n (x::xs)
= x :: take (n-1) xs
|
let rec take n xs
=
match n, xs
with
0, xs -> []
| n, []
-> failwith "take"
| n, x::xs
-> x :: take (n-1) xs
|
Does not have guards – use if
|
let rec fac
= function
0 -> 1
| n when
n>0 -> n * fac (n-1)
| _
-> raise Hell
|
fun foo(p as (x,y)) =
(x,p,y)
|
let foo ((x,y) as p)
= (x,p,y)
|
SML |
Ocaml |
type foo =
int * float *
string
|
type foo =
int * float *
string
|
val bar =
(0, 3.14, "hi")
|
let bar =
0, 3.14, "hi"
or
let bar =
(0, 3.14, "hi")
|
#2 bar
|
Does not have tuple selection – use pattern matching instead, e.g.
let
_,x,_
= bar
in x
|
#2
|
Does not have first-class selectors – use function instead, e.g.
function
_,x,_
-> x
or
fun
(_,x,_)
-> x
|
(inputLine stdIn, inputLine stdIn)
|
Evaluation order is undefined for tuples – use let , e.g.
let line1 = read_line ()
in
let line2 = read_line ()
in
(line1, line2)
|
SML |
Ocaml |
type foo =
{x:int, y:float,
s:string ref}
Note: record types need not be declared
|
type foo =
{x:int; y:float;
mutable s:string}
Note: mutable field does not have the same type as a reference
|
val bar =
{x=0, y=3.14,
s=ref ""}
|
let bar =
{x=0; y=3.14;
s=""}
|
#x bar
#y bar
!(#s bar)
|
bar.x
bar.y
bar.s
|
#x
|
Does not have first-class selectors – use function instead, e.g.
fun r ->
r.x
|
val {x=x,
y=y, s=s}
= bar
val {y=y, ...}
= bar
or
val {x, y, s}
= bar
val {y, ...}
= bar
|
let {x=x;
y=y; s=s}
= bar
let {y=y}
= bar
or (since Ocaml 3.12)
let {x; y; s}
= bar
let {y; _}
= bar
|
{x = 1,
y = #y bar,
s = #s bar}
|
{x = 1;
y = bar.y;
s = bar.s}
or
{bar with x = 1}
|
#s bar := "something"
|
bar.s
<- "something"
|
Does not have polymorphic fields
|
type bar =
{f:'a.'a -> int}
|
{a = inputLine stdIn, b = inputLine stdIn}
|
Evaluation order is undefined for records – use let , e.g.
let line1 = read_line ()
in
let line2 = read_line ()
in
{a = line1; b = line2}
|
SML |
Ocaml |
2 = 2
2 <> 3
|
2 = 2
2 <> 3
|
val r = ref 2
r = r
r <> ref 2
|
let r = ref 2
r == r
r != ref 2
|
(2, r) = (2, r)
(2, r) <> (2, ref 2)
|
Does not have a proper generic equality
(on one hand
(2, r) != (2, r), on the other
(2, r) = (2, ref 2))
|
case String.compare(x,y)
of
LESS => a
| EQUAL => b
| GREATER => c
|
match compare x y
with
n when n < 0
-> a
| 0 -> b
| _
-> c
|
fun f x y =
(x = y)
val f :
''a -> ''a ->
bool
|
let f x y =
(x = y)
val f :
'a -> 'a ->
bool
Does not have equality type variables – comparison allowed on all types
but may raise Invalid_argument exception
|
eqtype t
|
type t
Does not have equality types – comparison allowed on all types
but may raise Invalid_argument exception
|
SML |
Ocaml |
[1, 2, 3]
|
[1; 2; 3]
|
[(1, 2), (3, 4)]
|
[1, 2; 3, 4]
|
List.length xs
|
List.length xs
|
List.map f xs
|
List.map f xs
|
List.app f xs
|
List.iter f xs
|
List.foldl op+ 0 xs
List.foldr op- 100 xs
|
List.fold_left (+) 0 xs
List.fold_right (-) xs 100
|
List.all (fn x =>
x=0) xs
List.exists (fn x =>
x>0) xs
|
List.for_all (fun x ->
x=0) xs
List.exists (fun x ->
x>0) xs
|
val xys = ListPair.zip (xs, ys)
|
let xys = List.combine xs ys
|
val (xs, ys) = ListPair.unzip xys
|
let (xs, ys) = List.split xys
|
ListPair.app f (xs, ys)
|
List.iter2 f xs ys
|
[inputLine stdIn, inputLine stdIn]
|
Evaluation order is undefined for lists – use let , e.g.
let line1 = read_line ()
in
let line2 = read_line ()
in
[line1; line2]
|
SML |
Ocaml |
fun pyt(x,y) =
let
val xx
= x * x
val yy
= y * y
in
Math.sqrt(xx + yy)
end
|
let pyt x y =
let xx
= x *. x in
let yy
= y *. y in
sqrt (xx +. yy)
|
local
fun sqr x
= x * x
in
fun pyt(x,y)
= Math.sqrt(sqr x + sqr y)
end
|
Does not have local –
use global declarations, an auxiliary module, or
let
|
let
structure X
= F(A)
in
X.value + 10
end
Standard does not have structure declarations in
let but some implementations
support them
|
let module X
= F (A) in
X.value + 10
Experimental language extension
|
let open M in expr end
|
let open M in expr
Note: since Ocaml 3.12
|
let
datatype t
= A | B
exception E
in
expr
end
|
Does not have local type or exception declarations –
use global declarations or let
module
|
SML |
Ocaml |
functor F(X : S)
=
struct
(* ... *)
end
|
module F (X : S)
=
struct
(* ... *)
end
or
module F =
functor (X : S)
->
struct
(* ... *)
end
|
functor F(X :
sig
type t
end)
= body
structure X =
F (struct
type t = int
end)
or
functor F(type t)
= body
structure X =
F(type t = int)
|
module F (X :
sig
type t
end)
= body
module X =
F(struct
type t = int
end)
|
functor F (X : S)
(Y : T) = body
Standard does not have higher-order functors but several implementations
support them
|
module F (X : S)
(Y : T) = body
or
module F =
functor (X : S)
->
functor (Y : T)
-> body
|
functor F(X : S)
=
let
structure Y
= G(X)
in
Y.A
end
|
Does not have let for modules
|
SML |
Ocaml |
signature S =
sig
type t
eqtype u
val x
: t
structure M
: T
end
|
module type S
=
sig
type t
type u
val x
: t
module M
: T
end
|
functor F(X : S)
: S
Standard does not have higher-order functors but several implementations
support them
|
module F (X : S)
: S
or
module F :
functor (X : S)
-> S
|
include S
|
include S
|
Does not have open in signatures
|
open X
|
structure X : A
structure Y : B
sharing type X.t
= Y.u
|
Does not have sharing constraints –
use with
|
S where type t
= int
|
S with type t
= int
|
S where X = A.B
Standard does not have where
for structures but several implementations support it –
use where
type otherwise
|
S with X = A.B
|
signature S
=
sig
signature A
signature B = A
end
Standard does not have nested signatures but some implementations support them
|
module type S
=
sig
module
type A
module
type B = A
end
|