ocaml SML and OCaml, Side by Side Disclaimer
This is dump/copy of Standard ML and Objective Caml, Side by Side Original version by Jens Olsson, jenso@csd.uu.se . Last modified: 2011/01/18
You may ask “Why making copy instead of simple references to the source? ” - Because, I’d like to have it as is without looking around internet when ppl decide to delete it.
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).
Literals 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|]
Expressions SML Ocaml ~3*(1+7) div 2 mod 3 -3*(1+7)/2 mod 3 ~1.0/2.0 + 1.9*x -1.0 /. 2.0 +. 1.9 *. x a orelse b andalso c a || b && c or (deprecated) a or b & c
Functions 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
Control Flow 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
Value Declarations SML Ocaml val name = expr let name = expr fun f x y = expr let f x y = expr val rec fib = fn n => if n < 2 then n else fib(n-1) + fib(n-2) or fun fib n = if n < 2 then n else fib(n-1) + fib(n-2) let rec fib = fun n -> if n < 2 then n else fib (n-1) + fib (n-2) or let rec fib n = if n < 2 then n else fib (n-1) + fib (n-2)
Type Declarations 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
Matching 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)
Tuples 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)
Records 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}
References SML Ocaml val r = ref 0 let r = ref 0 !r !r or r. contents r := 1 r := 1 or r. contents <- 1 fun f(ref x) = x let f {contents= x} = x r1 = r2 r1 <> r2 r1 == r2 r1 != r2
Comparisons 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
Lists 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]
Strings SML Ocaml "Hello " ^ "world\n" "Hello " ^ "world\n" Int.toString 13 Real.toString 3.141 string_of_int 13 string_of_float 3.141 String.size s String.length s String.substring(s, 1, 2) String.sub s 1 2 String.sub(s, 0) String.get s 0 or s. [0] Strings are immutable, use CharArray for mutability String.set s 0 'F' or s. [0] <- 'F'
Array Functions SML Ocaml Array.array(20, 1.0) Array.make 20 1.0 Array.fromList xs Array.from_list xs Array.tabulate(30, fn x => x*x) Array.init 30 (fun x -> x*x) Array.sub(a, 2) Array.get a 2 or a.(2) Array.update(a, 2, x) Array.set a 2 x or a. (2) <- x Array.copy{src= a, si= 10, dst= b, di= 0, len= 20} Array.blit ~ src: a ~ src_pos: 10 ~ dst: b ~ dst_pos: 0 ~ len: 20
SML Ocaml fun copyFile(name1, name2) = let val file1 = TextIO.openIn name1 val s = TextIO.inputAll file1 val _ = TextIO.closeIn file1 val file2 = TextIO.openOut name2 in TextIO.output(file2, s); TextIO.closeOut file2 end let copy_file name1 name2 = let file1 = open_in name1 in let size = in_channel_length file1 in let buf = String.create size in really_input file1 buf 0 size; close_in file1; let file2 = open_out name2 in output_string file2 buf; close_out file2 Caveat: above code actually contains a race condition.
Exceptions SML Ocaml exception Hell exception Hell exception TotalFailure of string exception Total_failure of string raise TotalFailure "Unknown code" raise (Total_failure "Unknown code") expr handle TotalFailure s => ouch() try expr with Total_failure s -> ouch ()
Local Declarations 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
Structures SML Ocaml structure X :> S = struct type t = int val x = 0 end module X : S = struct type t = int let x = 0 end X :> S (X : S) X : S Does not have transparent signature ascription – use opaque ascription and with constraints open X include X local open X in (* ... *) end open X (* ... *)
Functors 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
Signatures 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