Getting started
Comments
(* This is a comment. *)
val z = 12;
val abs_of_z = if z < 0 then 0 - z else z;
arithmatic
val a = ~5; (* a is -5 *)
val v = x div y;
function
fun f(x1: t1, x2: t2, ... xn: tn) = e
tuple
(* tuple is a compound data structrue contains fixed size of elements with different types *)
val tuple = (e1, e2) (* with type t1 * t2, where t1 is the type of e1 and t2 is the type of e2 *)
(* access member of tuple *)
(#1 tuple)
list
(* list is a compound data structure contains arbitrary count of elements with same type*)
(* list construction *)
[7, 8, 9] (* with type int list *)
5::[6, 7, 8]
(* list accessing *)
null e (* evaluates to true if e evaluates to [] *)
hd e (* if e evaluates to [], raise exception, otherwise evaluates to the first element of e *)
tl e (* raise exemption if e evaluates to [] *)
let expression
(* let expression is used to create a scope
where a binding is in the environment
in and only in later bindings and body of the let expression*)
(* syntax: let bindings in expression end *)
options
(* t option is a type for any type t *)
(* construction *)
NONE (* hast type 'a option '*)
SOME e (* has type t option if e has type t *)
(* accessing *)
isSome: 'a option -> bool
valOf: 'a option -> 'a (* exception if given NONE *)
boolean operations
e1 andalso e2
e1 orelse e2
not e1
(* Language does not need andalse, orelse, not *)
(* e1 andalso e2 *)
if e1 then e2 else false
(* e1 orelse e2 *)
if e1 then true else e2
(* not e1 *)
if e1 then false else true
(* Comparisons for int values *)
(* = <> > < >= <= *)
(* > < >= <= can be used with real, but not 1 int and 1 real *)
(* = <> can by used with any "equality" type but not with real *)
records
val foo = {bar=3,baz=(1,[true,false],"world"),foo="hello"} :
{bar:int, baz:int * bool list * string, foo:string}
#bar foo (* val it = 3 : int *)
(* tuple is just a syntatic sugar for record with particular field name *)
type binding
datatype mytype = TwoInts of int * int
| Str of string
| Pizza
val a = Str "hi" : mytype
val b = Str : string -> mytype
val c = Pizza : mytype
val d = TwoInts(1+2, 3+4) : mytype
(* case expression *)
let x = Pizza;
case x of
Pizza => 1
Str s => String.size s
TwoInts(i1, i2) => i1 + i2
(* redundant case arm will cause compile time error *)
(* non exausted case arm will cause a warning and throw an exception when x is case of missing arms *)
(* type alias *)
type foo = int
The above code:
- adds a new type
mytype
to the environment. - adds constructoers to the environment: TwoInts, Str, Pizza
- a constructor is a function that makes values of the new type
TwoInts : int * int -> mytype
Str : string -> mytype
Pizza : mytype
polymorphic data types
datatype 'a option = NONE | SOME of 'a
datatype 'a mylist = Empty | Cons of 'a * 'a mylist
datatype ('a, 'b) tree =
Node of 'a * ('a, 'b) tree * ('a, 'b) tree
| Leaf of 'b;
(* '' denotes equality types, which can be use with = operator *)
''a list * ''a -> bool
function pattern matching
fun f x =
case x of
p1 => e1
| p2 => e2;
(* is equivilant to *)
fun f p1 = e1
| f p2 = e2
exceptions
exception MyException: exn
exception MyOtherException of int * int
(* raise exception *)
raise MyException
(* handle exception *)
e1 handle MyException => e2