6 OCAML has type inference: the system can often infer what the type of
7 an expression must be, based on the type of other known expressions.
9 For instance, if we type
13 The system replies with
15 val f : int -> int = <fun>
17 Since `+` is only defined on integers, it has type
20 - : int -> int -> int = <fun>
22 The parentheses are there to turn off the trick that allows the two
23 arguments of `+` to surround it in infix (for linguists, SOV) argument
29 In general, tuples with one element are identical to their one
35 though OCAML, like many systems, refuses to try to prove whether two
36 functional objects may be identical:
39 Exception: Invalid_argument "equal: functional value".
44 Booleans in OCAML, and simple pattern matching
45 ----------------------------------------------
47 Where we would write `true 1 2` in our pure lambda calculus and expect
48 it to evaluate to `1`, in OCAML boolean types are not functions
49 (equivalently, are functions that take zero arguments). Selection is
50 accomplished as follows:
52 # if true then 1 else 2;;
55 The types of the `then` clause and of the `else` clause must be the
58 The `if` construction can be re-expressed by means of the following
59 pattern-matching expression:
61 match <bool expression> with true -> <expression1> | false -> <expression2>
65 # match true with true -> 1 | false -> 2;;
70 # match 3 with 1 -> 1 | 2 -> 4 | 3 -> 9;;
76 All functions in OCAML take exactly one argument. Even this one:
82 Here's how to tell that `f` has been curry'd:
85 - : int -> int = <fun>
87 After we've given our `f` one argument, it returns a function that is
88 still waiting for another argument.
90 There is a special type in OCAML called `unit`. There is exactly one
91 object in this type, written `()`. So
96 Just as you can define functions that take constants for arguments
102 you can also define functions that take the unit as its argument, thus
105 val f : unit -> int = <fun>
107 Then the only argument you can possibly apply `f` to that is of the
108 correct type is the unit:
113 Let's have some fn: think of `rec` as our `Y` combinator. Then
115 # let rec f n = if (0 = n) then 1 else (n * (f (n - 1)));;
116 val f : int -> int = <fun>
120 We can't define a function that is exactly analogous to our ω.
121 We could try `let rec omega x = x x;;` what happens? However, we can
124 # let rec omega x = omega x;;
126 By the way, what's the type of this function?
127 If you then apply this omega to an argument,
131 the interpreter goes into an infinite loop, and you have to control-C
134 Oh, one more thing: lambda expressions look like this:
138 # (fun x -> x) true;;
141 (But `(fun x -> x x)` still won't work.)
143 So we can try our usual tricks:
145 # (fun x -> true) omega;;
148 OCAML declined to try to evaluate the argument before applying the
149 functor. But remember that `omega` is a function too, so we can
150 reverse the order of the arguments:
152 # omega (fun x -> true);;
156 Now consider the following variations in behavior:
158 # let test = omega omega;;
159 [Infinite loop, need to control c out]
161 # let test () = omega omega;;
162 val test : unit -> 'a = <fun>
165 - : unit -> 'a = <fun>
168 [Infinite loop, need to control c out]
170 We can use functions that take arguments of type unit to control
171 execution. In Scheme parlance, functions on the unit type are called
172 *thunks* (which I've always assumed was a blend of "think" and "chunk").