post latest content
[lambda.git] / rosetta.mdwn
1 ## Can you summarize the differences between your made-up language and Scheme, OCaml, and Haskell? ##
2
3 The made-up language we wet our toes in in week 1 is called Kapulet. (I'll tell you the story behind its name sometime.) The purpose of starting with this language is that it represents something of a center of gravity between Scheme, OCaml, and Haskell, and also lacks many of their idiosyncratic warts. One downside is that it's not yet implemented in a form that you can run on your computers. So for now, if you want to try out your code on a real mechanical evaluator, you'll need to use one of the other languages.
4
5 Also, if you want to read code written outside this class, or have others read your code, for these reasons too you'll need to make the shift over to one of the established languages.
6
7 We hope, though, that learning Kapulet first puts you in a position to make that shift more effortlessly, and also to more quickly see the places where there's underlying unity to Scheme, OCaml, and Haskell, despite their diverse syntaxes. (And idiosyncratic warts.)
8
9 [[!toc levels=2]]
10
11 ** *This page is still being written!* **
12
13
14
15 ### Comments
16
17     ...  # this is a comment in Kapulet, that goes until the end of the line
18
19     ...  ; this is a comment in Scheme, that goes until the end of the line
20
21     ...  -- this is a comment in Haskell, that goes until the end of the line
22
23 Note that for Haskell's comments, the `--` must be immediately followed by something like a space or a letter. `-->` does not begin a comment; it's a legal operator symbol.
24
25 OCaml doesn't have comments of that sort. It only has "block" comments like this:
26
27     (* ... *)
28
29 which may last for several lines. These comments *nest*, so that:
30
31     (* ... (* inner *) ... *)
32
33 is a single comment.
34
35 Haskell also has block comments, though it `{- writes them differently -}`.
36 Haskell's block comments also nest.
37
38 Racket and Scheme also have block comments, though they `#| write them differently |#`.
39 These block comments also nest. Another form of block comments is `#;( ... )`. Those may contain nested parentheses, and extend until the next *matching* `)`. So prefixing `#;` to a complex parenthesized expression is a way to turn the whole thing into a comment. (These two comment styles aren't part of the official Scheme standard, but they are widely implemented.)
40
41
42
43 ### Variable names
44
45 % Haskell's division into letter-based vs operators. Each can be "flagged" to temporarily behave as though it belonged to the other syntactic category (see below).
46
47
48
49 ### Infix operators and parentheses
50
51
52 Kapulet, OCaml, and Haskell all understand some expressions like `+` to be infix operators. So you would write:
53
54     1 + 2
55
56 not:
57
58     + 1 2
59
60 Although all three of these languages permits you to enclose an infix operator in parentheses to make a *section*, which no longer has infix syntax. In Kapulet, `( + )` is the same as λ `(x, y). x + y`, whereas in OCaml and Haskell it's a *curried* function, which we can write (in Kapulet syntax) as λ `x y. x + y`.
61
62 Kapulet and OCaml have some operators spelled with letters also taking infix syntax, such as `comp` in Kapulet or `mod` in OCaml. In Haskell, this is never the case: variables that begin with letters will only be treated as function-terms being applied to arguments when they're at the start of a list of expressions, and variables that are made of punctuation symbols, and not enclosed in parentheses, will only be treated as infix operators. However, Haskell permits you to temporarily flag a letter-based function name to behave like an infix operator, by enclosing it in `` ` `` marks. Thus in Haskell you can write:
63
64     3 `mod` 2
65
66 But without the `` ` ``, you'd have to write: `mod 3 2`.
67
68 Scheme has no infix operators. It ruthlessly demands that all functions that are to be applied to arguments come at the start of a list of expressions, regardless of whether those functions are spelled using letters, punctuation symbols, or a mix of the two. Thus in Scheme one always writes:
69
70     (+ 3 2)
71
72 and the like. Moreover, in Scheme parentheses are never optional and never redundant. In contexts like this, the parentheses are necessary to express that the function is being applied; `+ 3 2` on its own is not a complete Scheme expression. And if the `+` were surrounded by its own parentheses, as in:
73
74     ((+) 3 2)
75
76 what that would mean would be that `+` is first being applied to *zero* arguments, which is different from not applying it all. (In Kapulet, OCaml, and Haskell, one would write that `f` is being applied to "zero arguments" like this: `f ()`.) Scheme helpfully defines the result of applying `+` to zero arguments to be `0`. So then `((+) 3 2)` would evaluate to whatever `(0 3 2)` does, and that's an error, because `0` is not a function.
77
78 Note that `(0 3 2)`, although it *is*, qua expression, a list of numbers, does not evaluate to a list. To get an expression that *evaluates to* that list, you'd have to use `(list 0 3 2)` or `'(0 3 2)`. (Notice the initial `'`.)
79
80 In Scheme, you can also do `(+ 3 2 10)`, and so on. You only have to write `(+ (+ 3 2) 10)` if you really want to.
81
82 % Parentheses have other roles in Scheme, too.
83
84 In Scheme, the default style for defining functions is as taking several arguments simultaneously, that is the *uncurried* style. In OCaml and Haskell, the default style is to define them *curried*. Curried functions can easily be partially applied:
85
86     (* OCaml *)
87     let add  = fun x y -> x + y in
88     let add2 = add 2 in
89         add2 3
90     ;;
91
92 will result in `5`.
93
94 In Scheme, the default would be to define `add` like this:
95
96     (define add (lambda (x y) (+ x y)))
97
98 Then you cannot say `(add 2)`, because `add` will be expecting two arguments, but you only supplied one. You can however define curried functions in Scheme, it's just more laborious:
99
100     (define curried_add (lambda (x) (lambda (y) (+ x y))))
101     (define add2 (curried_add 2))
102     (add2 3)
103
104 will result in `5`. This is the best one can do in official Scheme, but there are various syntax extensions and macros out there to make it possible to write this sort of thing more succinctly.
105
106 OCaml and Haskell also permit defining functions in uncurried form:
107
108     (* OCaml *)
109     let add  = fun (x, y) -> x + y in
110     let add2 = fun add 2 in ...
111
112 Here the last displayed line will fail, because `add` expects as its argument a tuple of two numbers.
113
114 Kapulet is close to OCaml and Haskell; though for pedagogical reasons I started out introducing uncurried definitions.
115
116 As we mentioned, in Kapulet, OCaml, and Haskell, there is a shorthand that enables you to write things like:
117
118     # Kapulet
119     let
120       ten_minus match lambda x. 10 - x;
121       and_ys    match lambda x. x & ys
122     in (ten_minus, and_ys)
123
124 like this:
125
126     # Kapulet
127     let
128       ten_minus match (10 - );
129       and_ys    match ( & ys)
130     in (ten_minus, and_ys)
131
132 There are just minor differences between these languages. First, OCaml doesn't have the `( + 10)` or `(10 + )` forms, but only the `( + )`. Second, as a special case, OCaml doesn't permit you to do this with its list-consing operator `::`. You have to write `fun x xs -> x :: xs`, not `( :: )`. Whereas in Kapulet `( & )`, `(x & )`, and `( & xs)` are all sections using its sequence-consing operator `&`; and in Haskell, `( : )`, `(x : )`, and `( : xs)` are the same.
133
134 Thirdly, in Kapulet, `( - 10)` also expresses λ `x. x - 10` (consistently with `(10 - )`), but Haskell (and OCaml) treat this form differently, and interpret it as meaning the integer `- 10`. Here's how to express some things in Kapulet:
135
136     # Kapulet
137     (0 - 2)
138     ( - 2)         # ( - 2) 10 == 8
139     (0 - )
140     ( - ) (5, 3)
141     
142
143 and here are their translations into Haskell:
144
145     -- Haskell
146     ( -2 )
147     (subtract 2)  -- subtract 2 10 == 8
148     negate        -- (0 - ) also works
149     ( - ) 5 3
150
151 OCaml expresses `(0 - )` or `negate` as `~-`. You can write `3 * (0 - 2)` in OCaml as either `3 * ( -2 )` or as `3 * ~-2`.
152
153 I know all these languages fairly well, and I still find this last issue difficult to keep track of. You may be starting to understand why I spoke of "warts."
154
155
156 ### Equality and Booleans
157
158 The relation that's written `==` in Kapulet is also written that way in Haskell. That symbol means something else in OCaml, having to do with mutable reference cells; to get the same notion in OCaml one writes just a single `=`. The negation of this notion is written `!=` in Kapulet, `/=` in Haskell, and `<>` in OCaml. (Again, `!=` means something else in OCaml.)
159
160 The relations that are written `and`, `or`, and `not` are written in Haskell and OCaml as `&&`, `||`, and `not`. (Haskell uses `and` and `or` to express functions that form the conjunction or disjunction of every `Bool` value in a List of such. OCaml permits `or` as an old synonym for `||`, but discourages using that spelling. OCaml also permits `&` as an old, discouraged synonym for `&&`.)
161
162 Scheme %%
163
164 The values that are written `'true` and `'false` in Kapulet are written in Haskell as `True` and `False`, and in OCaml as just `true` and `false`. They're written `#t` and `#f` in Scheme, but in Scheme in many contexts any value that isn't `#f` will behave as though it were `#t`, even values you might think are more "false-ish", like `0` and the empty list. Thus `(if 0 'yes 'no)` will evaluate to `'yes`.
165
166 Scheme recognizes the values `'true` and `'false`, but it treats `'false` as distinct from `#f`, and thus as a "true-ish" value, like all of its other values that aren't `#f`.
167
168
169
170 ### Sequences, Lists, and Tuples
171
172 In Kapulet, we have a notion I called a "sequence" which has the empty element `[]` and the cons-ing operator `&`, so that:
173
174     1 & 2 & 3 & []
175
176 can also be written:
177
178     [1, 2, 3]
179
180 Haskell is very similar, except that it calls these Lists, and its cons-ing operator is written `:`. OCaml also calls them `list`s, and its cons-operator is written `::`. (OCaml *also* uses `:`, but it uses it to deal with types, and Haskell in turn also uses `::`, but that's what *it* uses to deal with types. Grr.)
181
182 Kapulet writes the operator that concatenates or appends sequences as `&&`. Thus:
183
184     # Kapulet
185     [1, 2] && [3, 4, 5]
186
187 evaluates to `[1, 2, 3, 4, 5]`. Haskell writes this operator as `++`. In Haskell, a `String` is just a List of `Char`, so `++` is also the operator we use to append strings:
188
189     -- Haskell
190     "over" ++ "due"
191
192 evaluates to `"overdue"`. In OCaml, `string`s aren't implemented as `list`s, so their append operators are different: `^` for `string`s and `@` for `list`s:
193
194     (* OCaml *)
195     [1; 2] @ [3; 4; 5] ;;
196     "over" ^ "due" ;;
197
198 evaluate to `[1; 2; 3; 4; 5]` and `"overdue"`. Note that OCaml separates its `list` items with semicolons not commas. If you write `[1, 2, 3]` in OCaml, it will think that's a one-element list whose first element is a triple, that is, what you'd write in Haskell as `[(1, 2, 3)]`.
199
200 Here are some list functions in Kapulet:
201
202     length
203     (&&)
204     # following were defined in homework
205     empty?
206     tail
207     drop
208     take
209     split
210     filter
211     partition
212     map
213     map2
214     # following were defined in extra credit
215     unmap2
216     takewhile
217     dropwhile
218     reverse
219     # new functions
220     concat       # converts [[10, 20], [30], [], [40, 50]] to [10, 20, 30, 40, 50] (only merging a single layer of []s)
221     (mem)        # infix syntax, 2 mem [1, 2, 3] == 'true
222     nth          # nth [10, 20, 30] 1 == 20, because first element is at position 0, fails if index is out of bounds
223     all? p xs    # all? odd? [1, 3, 5] == 'true
224     any? p xs    # any? even? [1, 3, 5] == 'false
225
226
227
228 Here are the corresponding functions in Haskell:
229
230     length
231     (++)
232     null
233     tail     -- compare head, which fails on []
234     drop     -- but these are curried functions, so you write `drop n xs`, not `drop (n, xs)` as in Kaupulet
235     take
236     splitAt
237     filter
238     Data.List.partition
239     map
240     zipWith  {- zip handles the special case where f is the function that forms ordered pairs
241                 both zipWith and zip stop with the shortest list -}
242     unzip    -- doesn't take an f argument, assumes (\(x, y) -> (x, y))
243     takeWhile
244     dropWhile
245     reverse
246     concat
247     elem     -- not infix syntax, but often written as: 2 `elem` [1, 2, 3]
248     (!!)     -- infix syntax: [10, 20, 30] !! 1 == 20; fails if index is out of bounds
249     all p xs
250     any p xs
251
252
253
254 Here they are in OCaml:
255
256     length
257     (@)          (* or List.append *)
258     (* no function corresponding to empty? *)
259     List.tl      (* compare List.hd, which fails on [] *)
260     (* no function corresponding to drop or take *)
261     (* no function corresponding to split; OCaml uses List.split to mean something else *)
262     List.filter  (* also List.find_all *)
263     List.partition
264     List.map
265     List.map2    (* compare List.combine, like Haskell's zip
266                     both map2 and combine fail if the lists are different lengths *)
267     List.split   (* like Haskell's unzip, doesn't take an f argument *)
268     (* no function corresponding to takewhile or dropwhile *)
269     List.rev
270     List.concat  (* also List.flatten, which still only merges a single layer of []s *)
271     List.mem     (* not infix syntax *)
272     List.nth     (* List.nth [10; 20; 30] 1 = 20; fails if index is out of bounds *)
273     List.for_all p xs
274     List.exists p xs
275
276
277 How does all this look in Scheme? Well, Scheme has a notion they call a (proper) `list`, and also a notion they call a `vector`. There are also what Scheme calls "improper" `list`s, with `(cons 1 'nonlist)` or `'(1 . nonlist)`, where `'nonlist` is any non-list (here it's a `symbol`) being a special case. Let's ignore the improper `list`s. Scheme's (proper) `list`s and `vector`s each has a claim to correspond to Kapulet's sequences, Haskell's Lists, and OCaml's `list`s. Each if also somewhat different. The dominant differences are:
278
279 1.  these structures in Scheme can contain heterogenously-typed elements, including further `list`s and `vector`s in some positions but not in others
280 2.  in the official Scheme standard, `list`s and `vector`s are both *mutable* containers, that is, one and the same persisting `list` structure can have different
281 elements at different stages in a program's evaluation
282
283 Many Scheme implementations also provide immutable versions of `list`s and `vector`s, more closely approximating the sequences/lists in Kapulet, Haskell, and OCaml. With some configurations, Racket even makes the immutable versions the defaults. But none of these are yet part of the official Scheme standard. Also, difference 1 is present in all Scheme implementations. This makes Scheme's `list`s and `vector`s in some ways more akin to *tuples* in the other languages (to "proper" tuples in Kapulet).
284
285 There are also some differences in how `list`s are specified in Scheme versus the other languages. In Scheme, one writes the empty list like this:
286
287     (list)
288
289 and lists with more elements like this:
290
291     (list 10)
292     (list 10 x)
293     (list 10 x 'alpha)
294     (list 10 x 'alpha (list 'beta 'gamma) 'delta 20)
295
296 In the preceding, the `x` is a variable and is evaluated to be whatever value it's bound to in the context where the displayed expressions are being evaluated. If one has a list specification that contains no variables, no matter how deeply embedded, then a certain shorthand becomes available, using a `'` prefix, like this:
297
298     '()                          ; same as (list)
299     '(10)                        ; same as (list 10)
300     '(10 alpha)                  ; same as (list 10 'alpha)
301     '(10 alpha (beta gamma) 20)  ; same as (list 10 'alpha (list 'beta 'gamma) 20)
302
303 Scheme can also write <code>'<em>something</em></code> as <code>(quote <em>something</em>)</code>. (The `quote` is not a function being applied to some argument; this is a special syntax that only superficially *looks* like a function application.)
304
305
306 Here are the `list` functions in Scheme corresponding to the functions listed in the other languages:
307
308     cons              ; corresponds to Kaupulet's ( & ), Haskell's ( : ), OCaml's `::`
309     length
310     append            ; corresponds to Kapulet's ( && ), Haskell's ( ++ ), OCaml's ( @ )
311                       ; can be applied to one or more arguments
312     null?             ; corresponds to Kapulet's empty?, Haskell's null
313     car               ; corresponds to Haskell's head
314     cdr               ; corresponds to Kapulet's and Haskell's tail
315     (list-tail xs k)  ; corresponds to Kapulet's drop (k, xs); fails if out-of-bounds
316     ; no official function corresponding to take or split or filter or partition
317     map               ; corresponds to Kapulet's map and map2
318                       ; can take one or more list arguments
319     ; no official function corresponding to unmap2 or takewhile or dropwhile
320     reverse
321     ; no official function corresponding to concat
322     member            ; corresponds to Kapulet's (mem) and Haskell's elem
323     (list-ref xs k)   ; corresponds to Kapulet's `nth xs k`
324     ; no official function corresponding to all or any
325
326 All of the functions listed as missing from the official Scheme standard can be found it various add-on libraries, or you could define them yourself if you had to.
327
328
329
330
331
332
333
334
335
336 symbol=?
337
338 characters
339 #\c
340 #\xff
341 #\space
342 #\newline
343
344
345
346
347
348 ### Other functions
349
350 Same in all: `succ`, `pred`, `fst`, `snd`.
351
352 Same in Kapulet and Haskell (modulo the differences between multivalues and tuples), aren't predefined in OCaml: `id`, `const`, `flip`, `curry`, `uncurry`.
353
354 Kapulet's `(comp)` is Haskell's `( . )`; isn't predefined in OCaml.
355
356 Kapulet and Haskell both have `( $ )`; OCaml expresses as `( @@ )`. (OCaml also has `|>` to express the converse operation: `f x`, `f @@ x` and `x |> f` all mean the same.)
357
358 Kapulet's `odd?` and `even?` are Haskell's `odd`, `even`; aren't predefined in OCaml.
359
360 Kapulet's `swap` (defined in homework) is Haskell's `Data.Tuple.swap`.
361
362 Kapulet's `dup` isn't predefined in Haskell but can be easily expressed as `\x -> (x, x)`.
363
364
365
366
367
368
369 ### More to come ...
370
371 (This page is being worked on...)
372
373
374 ## Offsite Readings comparing Scheme, OCaml, and Haskell ##
375
376 FIXME
377
378 *   [Haskell for OCaml Programmers](http://science.raphael.poss.name/haskell-for-ocaml-programmers.pdf)
379 *   [Introduction to OCaml for Haskellers](http://foswiki.cs.uu.nl/foswiki/pub/Stc/BeyondFunctionalProgrammingInHaskell:AnIntroductionToOCaml/ocaml.pdf), [another](http://blog.ezyang.com/2010/10/ocaml-for-haskellers/)
380 *   Haskell Wiki on [OCaml](https://wiki.haskell.org/OCaml)
381 *   [ML Dialects and Haskell](http://hyperpolyglot.org/ml)
382 *   [Differences between Haskell and SML?](http://www.quora.com/What-are-the-key-differences-between-Haskell-and-Standard-ML?browse)
383 *   [Comparing SML to OCaml](http://www.mpi-sws.org/~rossberg/sml-vs-ocaml.html)
384
385 [[!toc levels=2]]
386
387 ** *This page is still being written!* **
388
389
390 ## Can you summarize the differences between your made-up language and Scheme, OCaml, and Haskell? ##
391
392 The made-up language we wet our toes in in week 1 is called Kapulet. (I'll tell you the story behind its name sometime.) The purpose of starting with this language is that it represents something of a center of gravity between Scheme, OCaml, and Haskell, and also lacks many of their idiosyncratic warts. One downside is that it's not yet implemented in a form that you can run on your computers. So for now, if you want to try out your code on a real mechanical evaluator, you'll need to use one of the other languages.
393
394 Also, if you want to read code written outside this class, or have others read your code, for these reasons too you'll need to make the shift over to one of the established languages.
395
396 We hope, though, that learning Kapulet first puts you in a position to make that shift more effortlessly, and also to more quickly see the places where there's underlying unity to Scheme, OCaml, and Haskell, despite their diverse syntaxes. (And idiosyncratic warts.)
397
398 ### Comments
399
400     ...  # this is a comment in Kapulet, that goes until the end of the line
401
402     ...  ; this is a comment in Scheme, that goes until the end of the line
403
404     ...  -- this is a comment in Haskell, that goes until the end of the line
405
406 Note that for Haskell's comments, the `--` must be immediately followed by something like a space or a letter. `-->` does not begin a comment; it's a legal operator symbol.
407
408 OCaml doesn't have comments of that sort. It only has "block" comments like this:
409
410     (* ... *)
411
412 which may last for several lines. These comments *nest*, so that:
413
414     (* ... (* inner *) ... *)
415
416 is a single comment.
417
418 Haskell also has block comments, though it `{- writes them differently -}`.
419 Haskell's block comments also nest.
420
421 Racket and Scheme also have block comments, though they `#| write them differently |#`.
422 These block comments also nest. Another form of block comments is `#;( ... )`. Those may contain nested parentheses, and extend until the next *matching* `)`. So prefixing `#;` to a complex parenthesized expression is a way to turn the whole thing into a comment. (These two comment styles aren't part of the official Scheme standard, but they are widely implemented.)
423
424
425
426 ### Variable names
427
428 % Haskell's division into letter-based vs operators. Each can be "flagged" to temporarily behave as though it belonged to the other syntactic category (see below).
429
430
431
432 ### Infix operators and parentheses
433
434
435 Kapulet, OCaml, and Haskell all understand some expressions like `+` to be infix operators. So you would write:
436
437     1 + 2
438
439 not:
440
441     + 1 2
442
443 Although all three of these languages permits you to enclose an infix operator in parentheses to make a *section*, which no longer has infix syntax. In Kapulet, `( + )` is the same as &lambda; `(x, y). x + y`, whereas in OCaml and Haskell it's a *curried* function, which we can write (in Kapulet syntax) as &lambda; `x y. x + y`.
444
445 Kapulet and OCaml have some operators spelled with letters also taking infix syntax, such as `comp` in Kapulet or `mod` in OCaml. In Haskell, this is never the case: variables that are made of letters are only treated as function terms being applied to arguments *when they're at the start* of a list of expressions; and variables that are made of punctuation symbols, and not enclosed in parentheses, will only be treated as infix operators. However, Haskell permits you to temporarily "flag" a letter-made function term to behave like an infix operator, by enclosing it in `` ` `` marks. Thus in Haskell you can write:
446
447     3 `mod` 2
448
449 But without the `` ` ``, you'd have to write: `mod 3 2`.
450
451 Scheme has no infix operators. It ruthlessly demands that all functions to be applied to arguments come at the start of a list of expressions, regardless of whether those functions are spelled using letters, punctuation symbols, or a mix of the two. Thus in Scheme one always writes:
452
453     (+ 3 2)
454
455 and the like. Moreover, in Scheme parentheses are never optional and never redundant. In contexts like this, the parentheses are necessary to express that the function is being applied; `+ 3 2` on its own is not a complete Scheme expression. And if the `+` were surrounded by its own parentheses, as in:
456
457     ((+) 3 2)
458
459 what that would mean is that `+` is first being applied to *zero* arguments, which is different from not applying it all. (In Kapulet, OCaml, and Haskell, one would write that `f` is being applied to "zero arguments" like this: `f ()`.) Scheme helpfully defines the result of applying `+` to zero arguments to be `0`. So `((+) 3 2)` would evaluate to whatever `(0 3 2)` does, and that's an error, because `0` is not a function.
460
461 Note that `(0 3 2)`, although it *is*, qua expression, a list of numbers, does not evaluate to a list. To get an expression that *evaluates to* that list, you'd have to use `(list 0 3 2)` or `'(0 3 2)`. (Notice the initial `'`.)
462
463 In Scheme, you can also write `(+ 3 2 10)`, and so on. You only have to write `(+ (+ 3 2) 10)` if you really want to.
464
465 % Parentheses have other roles in Scheme, too.
466
467 In Scheme, the default style for defining functions is as taking several arguments simultaneously, that is the *uncurried* style. In OCaml and Haskell, the default style is to define them *curried*. Curried functions can easily be partially applied:
468
469     (* OCaml *)
470     let add  = fun x y -> x + y in
471     let add2 = add 2 in
472         add2 3
473     ;;
474
475 will result in `5`.
476
477 In Scheme, the default would be to define `add` like this:
478
479     (define add (lambda (x y) (+ x y)))
480
481 Then you cannot say `(add 2)`, because `add` will be expecting two arguments, but you only supplied one. You can however define curried functions in Scheme, it's just more laborious:
482
483     (define curried_add (lambda (x) (lambda (y) (+ x y))))
484     (define add2 (curried_add 2))
485     (add2 3)
486
487 will result in `5`. This is the best one can do in official Scheme, but there are various syntax extensions and macros out there to make it possible to write this sort of thing more succinctly.
488
489 OCaml and Haskell also permit defining functions in uncurried form:
490
491     (* OCaml *)
492     let add  = fun (x, y) -> x + y in
493     let add2 = fun add 2 in ...
494
495 Here the last displayed line will fail, because `add` expects as its argument a tuple of two numbers.
496
497 Kapulet essentially works like OCaml and Haskell; though for pedagogical reasons I started out by introducing uncurried definitions, rather than the *curried* definitions those other languages predominantly use.
498
499 As we mentioned, in Kapulet, OCaml, and Haskell, there is a shorthand that enables you to write things like:
500
501     # Kapulet
502     let
503       ten_minus match lambda x. 10 - x;
504       and_ys    match lambda x. x & ys
505     in (ten_minus, and_ys)
506
507 like this:
508
509     # Kapulet
510     let
511       ten_minus match (10 - );
512       and_ys    match ( & ys)
513     in (ten_minus, and_ys)
514
515 There are just minor differences between these languages. First, OCaml doesn't have the `( + 10)` or `(10 + )` forms, but only the `( + )`. Second, as a special case, OCaml doesn't permit you to do this with its list-consing operator `::`. You have to write `fun x xs -> x :: xs`, not `( :: )`. Whereas in Kapulet `( & )`, `(x & )`, and `( & xs)` are all sections using its sequence-consing operator `&`; and in Haskell, `( : )`, `(x : )`, and `( : xs)` are the same.
516
517 Thirdly, in Kapulet, `( - 10)` also expresses &lambda; `x. x - 10` (consistently with `(10 - )`), but Haskell (and OCaml) treat this form differently, and interpret it as meaning the integer `- 10`. Here's how to express some things in Kapulet:
518
519     # Kapulet
520     (0 - 2)
521     ( - 2)         # ( - 2) 10 == 8
522     (0 - )
523     ( - ) (5, 3)
524     
525
526 and here are their translations into Haskell:
527
528     -- Haskell
529     ( -2 )
530     (subtract 2)  -- subtract 2 10 == 8
531     negate        -- (0 - ) also works
532     ( - ) 5 3
533
534 OCaml expresses `(0 - )` or `negate` as `~-`. You can write `3 * (0 - 2)` in OCaml as either `3 * ( -2 )` or as `3 * ~-2`.
535
536 I know all these languages fairly well, and I still find this last issue difficult to keep track of. You may be starting to understand why I spoke of "warts."
537
538
539 ### Equality and Booleans
540
541 The relation that's written `==` in Kapulet is also written that way in Haskell. That symbol means something else in OCaml, having to do with mutable reference cells; to get the same notion in OCaml one writes just a single `=`. The negation of this notion is written `!=` in Kapulet, `/=` in Haskell, and `<>` in OCaml. (Again, `!=` means something else in OCaml.)
542
543 The relations that are written `and`, `or`, and `not` are written in Haskell and OCaml as `&&`, `||`, and `not`. (Haskell uses `and` and `or` to express functions that form the conjunction or disjunction of every `Bool` value in a List of such. OCaml permits `or` as an old synonym for `||`, but discourages using that spelling. OCaml also permits `&` as an old, discouraged synonym for `&&`.)
544
545 Scheme %%
546
547 The values that are written `'true` and `'false` in Kapulet are written in Haskell as `True` and `False`, and in OCaml as just `true` and `false`. They're written `#t` and `#f` in Scheme, but in Scheme in many contexts any value that isn't `#f` will behave as though it were `#t`, even values you might think are more "false-ish", like `0` and the empty list. Thus `(if 0 'yes 'no)` will evaluate to `'yes`.
548
549 Scheme recognizes the values `'true` and `'false`, but it treats `'false` as distinct from `#f`, and thus as a "true-ish" value, like all of its other values that aren't `#f`.
550
551
552
553 ### Sequences, Lists, and Tuples
554
555 In Kapulet, we have a notion I called a "sequence" which has an empty form `[]` and a cons-ing operator `&`, so that:
556
557     1 & 2 & 3 & []
558
559 can also be written:
560
561     [1, 2, 3]
562
563 Haskell is very similar, except that it calls these Lists, and its cons-ing operator is written `:`. OCaml also calls them `list`s, and its cons-operator is written `::`. (OCaml *also* uses `:`, but it uses it to deal with types, and Haskell in turn also uses `::`, but that's what *it* uses to deal with types. Grr.)
564
565 Kapulet writes the operator that concatenates or appends sequences as `&&`. Thus:
566
567     # Kapulet
568     [1, 2] && [3, 4, 5]
569
570 evaluates to `[1, 2, 3, 4, 5]`. Haskell writes this operator as `++`. In Haskell, a `String` is just a List of `Char`, so `++` is also the operator we use to append strings:
571
572     -- Haskell
573     "over" ++ "due"
574
575 evaluates to `"overdue"`. In OCaml, `string`s aren't implemented as `list`s, so their append operators are different: `^` for `string`s and `@` for `list`s:
576
577     (* OCaml *)
578     [1; 2] @ [3; 4; 5] ;;
579     "over" ^ "due" ;;
580
581 evaluate to `[1; 2; 3; 4; 5]` and `"overdue"`. Note that OCaml separates its `list` items with semicolons not commas. If you write `[1, 2, 3]` in OCaml, it will think that's a one-element list whose first element is a triple, that is, what you'd write in Haskell as `[(1, 2, 3)]`.
582
583 Here are some list functions in Kapulet:
584
585     length
586     (&&)
587     # the following were defined in homework
588     empty?
589     tail
590     drop
591     take
592     split
593     filter
594     partition
595     map
596     map2
597     # the following were defined in extra credit
598     unmap2
599     takewhile
600     dropwhile
601     reverse
602     # new functions
603     concat       # converts [[10, 20], [30], [], [40, 50]]
604                  # to [10, 20, 30, 40, 50] (only merging a single layer of []s)
605     (mem)        # infix syntax, 2 mem [1, 2, 3] == 'true
606     nth          # nth [10, 20, 30] 1 == 20, because the first element
607                  # is at position 0; fails if index is out of bounds
608     all? p xs    # all? odd? [1, 3, 5] == 'true
609     any? p xs    # any? even? [1, 3, 5] == 'false
610
611
612
613 Here are the corresponding functions in Haskell:
614
615     length
616     (++)
617     null
618     tail     -- compare head, which fails on []
619     drop     {- but these are curried functions, so you write `drop n xs`
620                 not `drop (n, xs)` as in Kapulet -}
621     take
622     splitAt
623     filter
624     Data.List.partition
625     map
626     zipWith  {- zip handles the special case where f is the function that forms ordered pairs
627                 both zipWith and zip stop with the shortest list -}
628     unzip    -- doesn't take an f argument, assumes (\(x, y) -> (x, y))
629     takeWhile
630     dropWhile
631     reverse
632     concat
633     elem     -- not infix syntax, but often written as: 2 `elem` [1, 2, 3]
634     (!!)     -- infix syntax: [10, 20, 30] !! 1 == 20; fails if index is out of bounds
635     all p xs
636     any p xs
637
638
639
640 Here they are in OCaml:
641
642     length
643     (@)          (* or List.append *)
644     (* no function corresponding to empty? *)
645     List.tl      (* compare List.hd, which fails on [] *)
646     (* no function corresponding to drop or take *)
647     (* no function corresponding to split; OCaml uses List.split to mean something else *)
648     List.filter  (* also List.find_all *)
649     List.partition
650     List.map
651     List.map2    (* compare List.combine, like Haskell's zip
652                     both map2 and combine fail if the lists are different lengths *)
653     List.split   (* like Haskell's unzip, doesn't take an f argument *)
654     (* no function corresponding to takewhile or dropwhile *)
655     List.rev
656     List.concat  (* also List.flatten, which still only merges a single layer of []s *)
657     List.mem     (* not infix syntax *)
658     List.nth     (* List.nth [10; 20; 30] 1 = 20; fails if index is out of bounds *)
659     List.for_all p xs
660     List.exists p xs
661
662
663 How does all this look in Scheme? Well, Scheme has a notion they call a (proper) `list`, and also a notion they call a `vector`. There are also what Scheme calls "improper" `list`s, with `(cons 1 'nonlist)` or `'(1 . nonlist)`, where `'nonlist` is any non-list (here it's a `symbol`) being a special case. Let's ignore the improper `list`s. Scheme's (proper) `list`s and `vector`s each has a claim to correspond to Kapulet's sequences, Haskell's Lists, and OCaml's `list`s. Each is also somewhat different. The dominant differences are:
664
665 1.  these structures in Scheme can contain heterogenously-typed elements, including further `list`s and `vector`s in some positions but not in others
666 2.  in the official Scheme standard, `list`s and `vector`s are both *mutable* containers, that is, one and the same persisting `list` structure can have different
667 elements at different stages in a program's evaluation
668
669 Many Scheme implementations also provide immutable versions of `list`s and `vector`s, more closely approximating the sequences/lists in Kapulet, Haskell, and OCaml. With some configurations, Racket even makes the immutable versions the defaults. But none of these are yet part of the official Scheme standard. Also, difference 1 is present in all Scheme implementations. This makes Scheme's `list`s and `vector`s in some ways more akin to *tuples* in the other languages (to "proper" tuples in Kapulet).
670
671 There are also some differences in how `list`s are specified in Scheme versus the other languages. In Scheme, one writes the empty list like this:
672
673     (list)
674
675 and lists with more elements like this:
676
677     (list 10)
678     (list 10 x)
679     (list 10 x 'alpha)
680     (list 10 x 'alpha (list 'beta 'gamma) 'delta 20)
681
682 In the preceding, the `x` is a variable and is evaluated to be whatever value it's bound to in the context where the displayed expressions are being evaluated. If one has a list specification that contains no variables, no matter how deeply embedded, then a certain shorthand becomes available, using a `'` prefix, like this:
683
684     '()                          ; same as (list)
685     '(10)                        ; same as (list 10)
686     '(10 alpha)                  ; same as (list 10 'alpha)
687     '(10 alpha (beta gamma) 20)  ; same as (list 10 'alpha (list 'beta 'gamma) 20)
688
689 Scheme can also write <code>'<em>something</em></code> as <code>(quote <em>something</em>)</code>. (The `quote` is not a function being applied to some argument; this is a special syntax that only superficially *looks* like a function application.)
690
691
692 Here are the `list` functions in Scheme corresponding to the functions listed in the other languages:
693
694     cons              ; corresponds to Kapulet's ( & ), Haskell's ( : ), OCaml's `::`
695     length
696     append            ; corresponds to Kapulet's ( && ), Haskell's ( ++ ), OCaml's ( @ )
697                       ; can be applied to one or more arguments
698     null?             ; corresponds to Kapulet's empty?, Haskell's null
699     car               ; corresponds to Haskell's head
700     cdr               ; corresponds to Kapulet's and Haskell's tail
701     (list-tail xs k)  ; corresponds to Kapulet's drop (k, xs); fails if out-of-bounds
702     ; no official function corresponding to take or split or filter or partition
703     map               ; corresponds to Kapulet's map and map2
704                       ; can take one or more list arguments
705     ; no official function corresponding to unmap2 or takewhile or dropwhile
706     reverse
707     ; no official function corresponding to concat
708     member            ; corresponds to Kapulet's (mem) and Haskell's elem
709     (list-ref xs k)   ; corresponds to Kapulet's `nth xs k`
710     ; no official function corresponding to all or any
711
712 All of the functions listed as missing from the official Scheme standard can be found in various add-on libraries, or you could define them yourself if you had to.
713
714
715
716
717
718 <!--
719
720 symbol=?
721
722 characters
723 #\c
724 #\xff
725 #\space
726 #\newline
727
728
729
730
731
732 ### Other functions
733
734 Same in all: `succ`, `pred`, `fst`, `snd`.
735
736 Same in Kapulet and Haskell (modulo the differences between multivalues and tuples), aren't predefined in OCaml: `id`, `const`, `flip`, `curry`, `uncurry`.
737
738 Kapulet's `(comp)` is Haskell's `( . )`; isn't predefined in OCaml.
739
740 Kapulet and Haskell both have `( $ )`; OCaml expresses as `( @@ )`. (OCaml also has `|>` to express the converse operation: `f x`, `f @@ x` and `x |> f` all mean the same.)
741
742 Kapulet's `odd?` and `even?` are Haskell's `odd`, `even`; aren't predefined in OCaml.
743
744 Kapulet's `swap` (defined in homework) is Haskell's `Data.Tuple.swap`.
745
746 Kapulet's `dup` isn't predefined in Haskell but can be easily expressed as `\x -> (x, x)`.
747
748 -->
749
750
751
752 ### More to come ...
753
754 (This page is being worked on...)
755
756 FIXME
757
758
759 ## Offsite Readings comparing Scheme, OCaml, and Haskell ##
760
761
762 *   [Haskell for OCaml Programmers](http://science.raphael.poss.name/haskell-for-ocaml-programmers.pdf)
763 *   [Introduction to OCaml for Haskellers](http://foswiki.cs.uu.nl/foswiki/pub/Stc/BeyondFunctionalProgrammingInHaskell:AnIntroductionToOCaml/ocaml.pdf), [another](http://blog.ezyang.com/2010/10/ocaml-for-haskellers/)
764 *   Haskell Wiki on [OCaml](https://wiki.haskell.org/OCaml)
765 *   [ML Dialects and Haskell](http://hyperpolyglot.org/ml)
766 *   [Differences between Haskell and SML?](http://www.quora.com/What-are-the-key-differences-between-Haskell-and-Standard-ML?browse)
767 *   [Comparing SML to OCaml](http://www.mpi-sws.org/~rossberg/sml-vs-ocaml.html)
768
769
770
771
772 ## Why did you name these pages "Rosetta"? ##
773
774 The [Rosetta Stone](https://en.wikipedia.org/wiki/Rosetta_Stone) is a famous slab discovered during Napoleon's invasion of Egypt, that had the same decree written in ancient Greek (which modern scholars understood) and two ancient Egyptian scripts (which they didn't). The slab enabled us to recover understanding of those Egyptian scripts; and has since come to be a symbol for the simultaneous expression of a single idea in multiple languages. A number of websites do this for various programming languages:
775
776 <table><th>
777 <td>Scheme
778 <td>OCaml
779 <td>Haskell
780 <tr>
781 <td rowspan=10>&nbsp;
782 <td><a href="http://rosettacode.org/wiki/Category:Scheme">Rosetta Code</a>
783 <td><a href="http://rosettacode.org/wiki/Category:OCaml">Rosetta Code</a>
784 <td><a href="http://rosettacode.org/wiki/Category:Haskell">Rosetta Code</a>
785 <tr>
786 <td><a href="http://pleac.sourceforge.net/pleac_guile/index.html">PLEAC</a>
787 <td><a href="http://pleac.sourceforge.net/pleac_ocaml/index.html">PLEAC</a>
788 <td><a href="http://pleac.sourceforge.net/pleac_haskell/index.html">PLEAC</a>
789 <tr>
790 <td>n/a
791 <td colspan=2 align=center><hr><a href="http://langref.org/ocaml+haskell/solved">langref.org</a>
792 <tr>
793 <td><a href="http://www.codecodex.com/wiki/Category:Scheme">code codex</a>
794 <td><a href="http://www.codecodex.com/wiki/Category:Objective_Caml">code codex</a>
795 <td><a href="http://www.codecodex.com/wiki/Category:Haskell">code codex</a>
796 <tr>
797 <td><a href="http://community.schemewiki.org/?ninety-nine-scheme-problems">99 problems</a>
798 <td><a href="http://ocaml.org/learn/tutorials/99problems.html">99 problems</a>
799 <td><a href="https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems">99 problems</a>
800 </table>
801
802 See also the [Project Euler](https://projecteuler.net/) programming challenges.