(* CaML: a typed functional programming language, dialect of ML In CaML, syntactic expressions (objects) have types. A lot of types and expressions are defined for you in the CaML "core library" includes: int, real, string, and bool. *) (2 : int);; (2.0 : float);; (-7 : int);; (* this is a comment *) ("abc" : string);; (true : bool);; (* You can also define your own types - we'll do that later. But not just simple expressions - _every_ expression has a type: *) 1+2;; 2<3;; (2+3)=(4-5);; 2.0 +. 3.0;; (* note the different '+' *) -. 2.0;; (* also allowed: *) - 2.0;; 2 + 3.0;; (* cannot be typed! + requires identically typed args But you can *coerce*: *) float_of_int(2) +. 3.0;; let sq(x) = x * x;; let sq(x) = x *. x;; 3 / 10;; 3 quo 10;; 3.0 /. 10.0;; 2:int;; (2:int);; (* typing "judgements" like this must be parenthesized *) (* There are two more basic data structures, in addition to these: tuples and lists. A *tuple* refers to a pairing, triple, quadruple, or greater n-tuple of other elements, e.g. *) (1,2,3);; (1,2.0,"ab");; fst (2,3);; snd ("ab",4.5);; (* these accessors only work on pairs *) (2,(3.0,"ab"),"cd");; (* There's no such type as "tuple" --- the type assigned to these is a *product* of the types of the individual parts. Complex data types like tuples generally come with built-in functions that help us assemble and take apart objects of those types. This is a basic design principle for all data structures: along with the structures, you must also think about its *accessors*. In CaML, the only difference is that data structures are named by their types - so the functions are associated with types. Functions that assemble these complex structures are called *constructors*. The constructor for tuples is the (,) function. It has a special syntax - not really either infix or prefix. There's even a 0-tuple, written (). This tuple doesn't actually have a product type, because there's nothing to take the product of. Instead, we call its type *unit*. Functions on multiple arguments are actually functions on a single tuple argument! *) let f(x,y) = x*x + y;; f(2,3);; (2,3);; (* Functions that take apart data structures are called *selectors*. An n-tuple has n possible selectors - one that grabs each argument. The core library only defines the selectors for pairs (2-tuples). These are called fst and snd. You have to define the selectors you want for other values of n. A *list* is a binary, recursive data structure. There is an empty list, []: *) [];; (* and a constructor, ::, which builds a list out of some object plus a list object: *) 2::[];; 2::3;; (* the second argument must be a list *) []::[[2]];; (* but the first argument can be as well *) 1::2::3::[];; (* It gets pretty tedious writing these, so there's a special syntax: *) [1;2;3];; (* Notice that tuples use (..,..), lists use [..;..]. Notice also that list isn't exactly a type either. More on that below. The selectors for list are hd and tl - these grab the first and second components of the pair that is a list: *) hd [1;2;3];; tl [1;2;3];; hd (tl [1;2;3]);; hd tl [1;2;3];; (* CaML parser can't always determine associativity *) hd [[1;2];[3;4]];; hd (hd [[1;2];[3;4]]);; hd 3;; tl [];; (* Note the special error message - not a typing error *) let i(x) = hd (x::[]);; i(3);; (* By the way, sometimes :: is called *cons*, hd is called *car* and tl is called *cdr*. Dumb names, but you still might hear them. list is not a type. It's a *parametric type*. A parametric type is a kind of function that maps one or more types to types, rather than zero or more objects to objects. Parametric types are not functions, in CaML-speak, however. Functions map objects to objects. *) [1;2;3];; [1.0;2.0];; [[1;2];[3;4]];; tl [[[[[[[[[1]]]]]]]]];; (* What type would we assign to: *) [1;2;"ab"];; [1,2,"ab"];; (1,2,"ab");; (* lists are *homogeneous*, but tuples are not *) (1,2.0,"ab");; hd;; sq;; (* 'a is a *type variable*. CaML knows the type of hd, but notice that it has also *inferred* the type of sq - we didn't tell CaML this. This is very handy. *)