X-Git-Url: http://lambda.jimpryor.net/git/gitweb.cgi?p=lambda.git;a=blobdiff_plain;f=translating_between_OCaml_Scheme_and_Haskell.mdwn;h=b893896283a27cc5f027b3a1bd72561957835727;hp=ed2ce4a16d868b7abb85d41e70f0083606f4aaad;hb=8e24378981bd4095fe580475cf6a530e168965b1;hpb=e8b64639978778d2e79cf05bb476f42fa1c9527c diff --git a/translating_between_OCaml_Scheme_and_Haskell.mdwn b/translating_between_OCaml_Scheme_and_Haskell.mdwn index ed2ce4a1..b8938962 100644 --- a/translating_between_OCaml_Scheme_and_Haskell.mdwn +++ b/translating_between_OCaml_Scheme_and_Haskell.mdwn @@ -42,14 +42,17 @@ Additionally, the syntax of OCaml and SML is superficially much closer to Haskel * **Type Variants and Pattern Matching** If you want to reproduce this kind of OCaml code: - type lambda_expression = Var of char | Lam of char * lambda_expression | App of lambda_expression * lambda_expression;; + # type lambda_expression = Var of char | Lam of char * lambda_expression | App of lambda_expression * lambda_expression;; - let rec free_vars (expr : lambda_expression) : char list = + # let rec free_vars (expr : lambda_expression) : char list = match expr with | Var label -> [label] | Lam (label, body) -> remove label (free_vars body) | App (left, right) -> merge (free_vars left) (free_vars right);; + # free_vars (Lam ('x', (App (Var 'x', Var 'y'))));; + - : char list = ['y'] + in Scheme, you have two choices. First, the quick hack: ; we use the symbols 'var and 'lam as tags, and assume @@ -67,7 +70,7 @@ Additionally, the syntax of OCaml and SML is superficially much closer to Haskel Second, you can create real datatypes and pattern-match on them. There are several tools for doing this. I'll describe the `define-datatype` and `cases` forms developed for the book *Essentials of Programming Languages* (EoPL) by Friedman and Wand. - (Alternatives include the `struct` form in Racket, see . Also `define-record-type` from srfi-9 and srfi-57; see also .) + (Alternatives include [the `struct` form in Racket](http://docs.racket-lang.org/guide/define-struct.html). Also `define-record-type` from srfi-9 and srfi-57; see also [the r6rs libs](http://docs.racket-lang.org/r6rs-lib-std/r6rs-lib-Z-H-7.html).) Here is how the tools from EoPL work. You must begin your file either with `#lang eopl` or with the first two lines below: @@ -85,8 +88,10 @@ Additionally, the syntax of OCaml and SML is superficially much closer to Haskel (lam (label body) (remove label (free-vars body))) (app (left right) (remove-duplicates (append (free-vars left) (free-vars right)))))) + (free-vars (lam 'x (app (var 'x) (var 'y)))) + ; evaluates to '(y) -* Scheme has excellent support for working with implicit or "first-class" **continuations**, using either `call/cc` or any of various delimited continuation operators. See . +* Scheme has excellent support for working with implicit or "first-class" **continuations**, using either `call/cc` or any of various delimited continuation operators. See [the Racket docs](http://docs.racket-lang.org/reference/cont.html?q=shift&q=do#%28part._.Classical_.Control_.Operators%29). In Scheme you can use these forms by default (they're equivalent): @@ -126,7 +131,8 @@ Additionally, the syntax of OCaml and SML is superficially much closer to Haskel There is also a library for using *undelimited* continuations in OCaml, but it's shakier than Oleg's delimited continuation library. -We won't say any more about translating to and from Scheme. +There are some more hints about Scheme [here](/assignment8/) and [here](/week1/). We won't say any more here. + #Haskell and OCaml# @@ -134,9 +140,9 @@ We won't say any more about translating to and from Scheme. We will however try to give some general advice about how to translate between OCaml and Haskell. * Again, it may sometimes be useful to [try Haskell in your web browser](http://tryhaskell.org/) -* There are many Haskell tutorials and textbooks available. This is probably the most actively developed: [Haskell Wikibook](http://en.wikibooks.org/wiki/Haskell) -* [Yet Another Haskell Tutorial](http://www.cs.utah.edu/~hal/docs/daume02yaht.pdf) (much of this excellent book has supposedly been integrated into the Haskell Wikibook) -* All About Monads has supposedly also been integrated into the Haskell Wikibook +* There are many Haskell tutorials and textbooks available. This is probably the most actively developed: [Haskell wikibook](http://en.wikibooks.org/wiki/Haskell) +* [Yet Another Haskell Tutorial](http://www.cs.utah.edu/~hal/docs/daume02yaht.pdf) (much of this excellent book has supposedly been integrated into the Haskell wikibook) +* All About Monads has supposedly also been integrated into the Haskell wikibook * (A not-so-)[Gentle Introduction to Haskell](http://web.archive.org/web/http://www.haskell.org/tutorial/) (archived) * [Learn You a Haskell for Great Good](http://learnyouahaskell.com/) @@ -145,7 +151,7 @@ We will however try to give some general advice about how to translate between O * In Haskell, you say a value has a certain type with: `value :: type`. You express the operation of prepending a new `int` to a list of `int`s with `1 : other_numbers`. In OCaml it's the reverse: you say `value : type` and `1 :: other_numbers`. -* In Haskell, type names and constructors both begin with capital letters, and type variables always appear after their constructors, in Curried form. And the primary term for declaring a new type is `data` (short for [[!wikipedia algebraic datatype]]). So we have: +* In Haskell, type names and constructors both begin with capital letters, and type variables always appear after their constructors, in Curried form. And the primary term for declaring a new type is `data` (short for [[!wikipedia algebraic data type]]). So we have: data Either a b = Left a | Right b; data FooType a b = Foo_constructor1 a b | Foo_constructor2 a b; @@ -177,15 +183,17 @@ We will however try to give some general advice about how to translate between O type Weight = Integer type Person = (Name, Address) -- supposing types Name and Address to be declared elsewhere - then you can use a value of type `Integer` wherever a `Weight` is expected, and vice versa. `newtype` and `data` on the other hand, create genuinely new types. `newtype` is basically just an efficient version of `data` that you can use in special circumstances. `newtype` must always take one type argument and have one value constructor. For example: + then you can use a value of type `Integer` wherever a `Weight` is expected, and vice versa. + + `newtype` and `data` on the other hand, create genuinely new types. `newtype` is basically just an efficient version of `data` that you can use in special circumstances. `newtype` must always take one type argument and have one value constructor. For example: newtype PersonalData a = PD a You could also say: - data PersonalData a = PD a + data PersonalData2 a = PD2 a - And `data` also allows multiple type arguments, and multiple variants and value constructors. + And `data` also allows multiple type arguments, and multiple variants and value constructors. OCaml just uses the one keyword `type` for all of these purposes: @@ -193,6 +201,12 @@ We will however try to give some general advice about how to translate between O type person = name * address;; type 'a personal_data = PD of 'a;; +* When a type only has a single variant, as with PersonalData, Haskell programmers will often use the same name for both the type and the value constructor, like this: + + data PersonalData3 a = PersonalData3 a + + The interpreter can always tell from the context when you're using the type name and when you're using the value constructor. + * The type constructors discussed above took simple types as arguments. In Haskell, types are also allowed to take *type constructors* as arguments: data BarType t = Bint (t Integer) | Bstring (t string) @@ -658,6 +672,11 @@ Haskell has more built-in support for monads, but one can define the monads one which can be translated straightforwardly into OCaml. + For more details, see: + + * [Haskell wikibook on do-notation](http://en.wikibooks.org/wiki/Haskell/do_Notation) + * [Do-notation considered harmful](http://www.haskell.org/haskellwiki/Do_notation_considered_harmful) + * If you like the Haskell do-notation, there's [a library](http://www.cas.mcmaster.ca/~carette/pa_monad/) you can compile and install to let you use something similar in OCaml. * In order to do any printing, Haskell has to use a special `IO` monad. So programs will look like this: