The functional programming literature tends to use one of four languages: Scheme, OCaml, Standard ML (SML), or Haskell. With experience, you'll grow comfortable switching between these. At the beginning, though, it can be confusing.
-The easiest translations are between OCaml and SML. These languages are both derived from a common ancestor, ML. For the most part, the differences between them are only superficial. [Here's a translatio nmanual](http://www.mpi-sws.org/~rossberg/sml-vs-ocaml.html).
+The easiest translations are between OCaml and SML. These languages are both derived from a common ancestor, ML. For the most part, the differences between them are only superficial. [Here's a translation manual](http://www.mpi-sws.org/~rossberg/sml-vs-ocaml.html).
In some respects these languages are closer to Scheme than to Haskell: Scheme, OCaml and SML all default to call-by-value evaluation order, and all three have native syntax for mutation and other imperative idioms (though that's not central to their design). Haskell is different in both respects: the default evaluation order is call-by-name (strictly speaking, it's "call-by-need", which is a more efficient cousin), and the only way to have mutation or the like is through the use of monads.
class Eq a where
(==) :: a -> a -> Bool
- This declares the type-class `Eq`; in order to belong to this class, a type `a` will have to supply its own implementation of the function ==, with the type a -> a -> Bool. Here is how the `Integer` class signs up to join the type-class:
+ This declares the type-class `Eq`; in order to belong to this class, a type `a` will have to supply its own implementation of the function `==`, with the type `a -> a -> Bool`. Here is how the `Integer` class signs up to join this type-class:
instance Eq Integer where
- x == y = ...
+ x == y = ... some definition for the Integer-specific version of that function here ...
Type expressions can be conditional on some of their parameters belonging to certain type-classes. For example:
says that if `a` belongs to the typeclass `Eq`, then so too does `Tree a`, and in such cases here is the implementation of `==` for `Tree a`...
-* OCaml doesn't have type-classes. You can do soemthing similar with OCaml modules that take are parameterized on other modules. Again, [see here](/code/tree_monadize.ml) for an example.
+* OCaml doesn't have type-classes. You can do something similar with OCaml modules that take are parameterized on other modules. Again, [see here](/code/tree_monadize.ml) for an example.
* Some specific differences in how certain types are expressed. This block in Haskell:
Prelude> let x = () :: ()
Prelude> let x = (1, True) :: (Int, Bool)
-corresponds to this block in OCaml:
+ corresponds to this block in OCaml:
# type 'a option = None | Some of 'a;;
type 'a option = None | Some of 'a
List.map (fun x -> x * x) (List.filter odd [1..10]);;
-* In Haskell, the expressions "abc" and ['a','b','c'] are equivalent. (Strings are just lists of chars. In OCaml, these expressions have two different types.
+* In Haskell, the expressions "abc" and ['a','b','c'] are equivalent. (Strings are just lists of chars.) In OCaml, these expressions have two different types.
Haskell uses the operator `++` for appending both strings and lists (since Haskell strings are just one kind of list). OCaml uses different operators:
- "string1" ^ "string2"
- ['s';'t'] @ ['r';'i';'n';'g']
- (* or equivalently *)
- List.append ['s';'t'] ['r';'i';'n';'g']
+ # "string1" ^ "string2";;
+ - : string = "string1string2"
+ # ['s';'t'] @ ['r';'i';'n';'g'];;
+ - : char list = ['s'; 't'; 'r'; 'i'; 'n'; 'g']
+ # (* or equivalently *)
+ List.append ['s';'t'] ['r';'i';'n';'g'];;
+ - : char list = ['s'; 't'; 'r'; 'i'; 'n'; 'g']
#Let and Where#
* In Haskell one says:
-- declare a record type
- data Color = C { red, green, blue :: Int }
+ data Color = Col { red, green, blue :: Int }
-- create a value of that type
- let c = C { red = 0, green = 127, blue = 255 }
+ let c = Col { red = 0, green = 127, blue = 255 }
In OCaml one says instead:
- type color = { red : int; green : int; blue : int};;
+ type color = { red : int; green : int; blue : int };;
let c = { red = 0; green = 127; blue = 255 }
- Notice that OCaml doesn't use any value constructor `C`. The record syntax `{ red = ...; green = ...; blue = ... }` is by itself the constructor. The record labels `red`, `green`, and `blue` cannot be re-used for any other record type.
+ Notice that OCaml doesn't use any value constructor `Col`. The record syntax `{ red = ...; green = ...; blue = ... }` is by itself the constructor. The record labels `red`, `green`, and `blue` cannot be re-used for any other record type.
* In Haskell, one may have multiple constructors for a single record type, and one may re-use record labels within that type, so long as the labels go with fields of the same type:
data FooType = Constructor1 {f :: Int, g :: Float} | Constructor2 {f :: Int, h :: Bool}
-* In Haskell, one can extract the field of a record like this:
+* In Haskell, one can extract a single field of a record like this:
- let c = C { red = 0, green = 127, blue = 255 }
+ let c = Col { red = 0, green = 127, blue = 255 }
in red c -- evaluates to 0
- In OCaml:
+ In OCaml one says:
let c = { red = 0; green = 127; blue = 255 }
in c.red (* evaluates to 0 *)
* In both languages, there is a special syntax for creating a copy of an existing record, with some specified fields altered. In Haskell:
let c2 = c { green = 50, blue = 50 }
- -- evaluates to C { red = red c, green = 50, blue = 50 }
+ -- evaluates to Col { red = red c, green = 50, blue = 50 }
In OCaml:
* One pattern matches on records in similar ways. In Haskell:
- let C { red = r, green = g } = c
+ let Col { red = r, green = g } = c
in r
In OCaml:
In Haskell:
- makegray c@(C { red = r} ) = c { green = r, blue = r }
+ makegray c@(Col { red = r } ) = c { green = r, blue = r }
is equivalent to:
- makegray c = let C { red = r } = c
+ makegray c = let Col { red = r } = c
in { red = r, green = r, blue = r }
In OCaml it's:
| x' when x' = 0 -> 0
| _ -> -1
-* In Haskell the equality comparison operator is `==`, and the non-equality operator is `/=`. In OCaml, `==` expresses "physical identity", which has no analogue in Haskell because Haskell has no mutable types. See our discussion of "Four grades of mutable involvement" in the [[Week9]] notes. In OCaml the operator corresponding to Haskell's `==` is just `=`, and the corresponding non-equality operator is `<>`.
+* In Haskell the equality comparison operator is `==`, and the non-equality operator is `/=`. In OCaml, `==` expresses "physical identity", which has no analogue in Haskell because Haskell has no mutable types. See our discussion of "Four grades of mutation involvement" in the [[Week9]] notes. In OCaml the operator corresponding to Haskell's `==` is just `=`, and the corresponding non-equality operator is `<>`.
* In both Haskell and OCaml, one can use many infix operators as prefix functions by parenthesizing them. So for instance:
will work in both languages. One notable exception is that in OCaml you can't do this with the list constructor `::`:
- # (::) 1 [1;2];;
- Error: Syntax error
- # (fun x xs -> x :: xs) 1 [1; 2];;
- - : int list = [1; 1; 2]
+ # (::) 1 [1;2];;
+ Error: Syntax error
+ # (fun x xs -> x :: xs) 1 [1; 2];;
+ - : int list = [1; 1; 2]
* Haskell also permits two further shortcuts here that OCaml has no analogue for. In Haskell, in addition to writing: