From 42a240893db5a42a4c1150d2abb1075b1982d54a Mon Sep 17 00:00:00 2001 From: Jim Pryor Date: Sat, 4 Dec 2010 09:22:39 -0500 Subject: [PATCH] translating tweaks Signed-off-by: Jim Pryor --- translating_between_OCaml_Scheme_and_Haskell.mdwn | 55 ++++++++++++----------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/translating_between_OCaml_Scheme_and_Haskell.mdwn b/translating_between_OCaml_Scheme_and_Haskell.mdwn index 7b66cb39..171f644e 100644 --- a/translating_between_OCaml_Scheme_and_Haskell.mdwn +++ b/translating_between_OCaml_Scheme_and_Haskell.mdwn @@ -1,6 +1,6 @@ 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. @@ -205,10 +205,10 @@ So we have: 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: @@ -225,7 +225,7 @@ So we have: 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: @@ -237,7 +237,7 @@ So we have: 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 @@ -299,14 +299,17 @@ corresponds to this block in OCaml: 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# @@ -369,27 +372,27 @@ Haskell and OCaml both have `records`, which are essentially just tuples with a * 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 *) @@ -397,7 +400,7 @@ Haskell and OCaml both have `records`, which are essentially just tuples with a * 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: @@ -406,7 +409,7 @@ Haskell and OCaml both have `records`, which are essentially just tuples with a * 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: @@ -416,11 +419,11 @@ Haskell and OCaml both have `records`, which are essentially just tuples with a 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: @@ -486,7 +489,7 @@ Haskell and OCaml both have `records`, which are essentially just tuples with a | 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: @@ -494,10 +497,10 @@ Haskell and OCaml both have `records`, which are essentially just tuples with a 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: -- 2.11.0