Permalink
Browse files

Imported pure-fun

  • Loading branch information...
1 parent b55776d commit fbf915aaacf2ad531afe052b8e76744d57e6336e @mmottl mmottl committed May 1, 2006
Showing with 1,927 additions and 0 deletions.
  1. +10 −0 Changes
  2. +142 −0 README
  3. +52 −0 README.okasaki
  4. +1 −0 VERSION
  5. +130 −0 chp2.ml
  6. +181 −0 chp3.ml
  7. +83 −0 chp4.ml
  8. +184 −0 chp5.ml
  9. +287 −0 chp6.ml
  10. +276 −0 chp7.ml
  11. +268 −0 chp8.ml
  12. +313 −0 chp9.ml
View
@@ -0,0 +1,10 @@
+2006-03-29: Removed superfluous thunking of "empty" values in polymorphic
+ datastructures due to relaxed value restriction in new
+ OCaml-releases.
+
+2002-07-23: Small beautification.
+
+2001-06-05: Made code more idiomatic.
+ Implemented stubs in chapter 8.
+
+1999-04-09: Initial release.
View
@@ -0,0 +1,142 @@
+These files contain an SML-to-OCAML translation of source examples taken
+from the following book:
+
+ Purely Functional Data Structures
+ Chris Okasaki
+ Cambridge University Press, 1998
+ Copyright (c) 1998 Cambridge University Press
+
+
+Some short notes regarding my port:
+
+I have tried to stick as close as possible to the original code, but
+sometimes this cannot be done.
+
+The first nine chapters are translated now. Although there are two further
+chapters, I will not translate them anymore, because of restrictions
+that exist not only in SML but also in OCAML:
+
+The basic idea of chapter 10 and 11 is the application of techniques
+called "structural decomposition" and "structural abstraction" (10)
++ their combination and generalization with ideas in chapter 9 (lazy
+redundant binary numbers) in a framework called "implicit recursive
+slowdown" (11).
+
+Structural decomposition and abstraction require socalled "polymorphic
+recursion". Type inference is unfortunately undecidable in the presence
+of the latter, so neither OCAML nor SML support it.
+
+Thus, the author presents two versions for his examples in these chapters:
+one which does not pass the type checker because of polymorphic recursion
+(for demonstration purposes only), anotherone for showing how to work
+around this restriction.
+
+In a question posted to the OCAML-list, I learnt from the OCAML-developers
+that they are actively researching ways to circumvent the problem of
+polymorphic recursion (e.g. with "forward"-definitions that allow the
+user to restrict the type of a polymorphically recursive definition). In
+the not unlikely case that they succeed, I will continue to translate
+the remaining chapters.
+
+If someone wants to translate the "workaround"-solutions, I will be glad
+to include them in this distribution. In the meanwhile I will wait and
+see what happens in future OCAML-releases.
+
+
+Notes on efficiency:
+
+Because the data structures are purely functional, they profit a lot from
+garbage collector settings. In case you find that some of them are not
+efficient enough, you might want to raise the memory overhead parameter
+of the garbage collector. See "http://caml.inria.fr/ocaml/speed.html"
+for more details. Performance is in general excellent.
+
+
+The following rules / differences to the original sources exist:
+
+* No base module
+
+Since there is hardly anything really necessary in the base module,
+I copied the few relevant declarations into the modules. This allows
+easier testing, because the modules do not depend on others.
+
+
+* Syntax
+
+Names are created by the following rules:
+
+ * Module types are written in capitals. If they consist of more than
+ a word, an underscore ('_') is placed between the words.
+
+ * Names of exceptions follow the same rule as modules types.
+
+ * Module implementations have to start with a capital letter, the
+ rest of the name is lowercase - except if it consists of more than
+ one word. In this case the first letter of the following word is
+ uppercase. There is no underscore between words.
+
+
+* Currying of function parameters
+
+Currying is not used anywhere in the original source. I have tried to
+curry parameters, where it makes sense. Tuples that represent a named type
+(e.g. some data structure) are *not* curried in functions that are hidden
+by a signature restriction -> more comprehensible. Functions offered
+via the module interface (signature) do not reveal such implementation
+details (concrete type) anyway, of course.
+
+
+* Superfluous bindings
+
+If a parameter is never used in a following expression, it is not bound
+to any name, but '_' will hold its place.
+
+
+* Lazy evaluation
+
+Lazy evaluation is neither an integral part of SML nor of OCAML.
+The original author uses an experimental syntax for describing data
+structures that have to be evaluated lazily. To give people a hint,
+how lazy behaviour can be done, I have used the "Lazy"-module found in
+the standard distribution of OCAML.
+
+To make the syntax at least a bit more similar to the original, I
+have introduced the prefix operator '!$', which stands for 'force" -
+it forces evaluation of a lazy expression. To make an expression lazy,
+the expression 'lazy' is used.
+
+There is a test function at the end of the translation of chapter 4,
+the chapter in which lazy evaluation and streams (= lazy lists) are
+introduced. Uncomment it to try out, how lazy evaluation behaves.
+
+
+* Interface QUEUE
+
+Due to the impossibility to safely generalize expressions in modules
+when parameterized types are used together with "Lazy.t", I had to change
+the interface (most convenient workaround):
+
+Instead of the value
+
+ val empty : 'a queue
+
+the function
+
+ val empty : unit -> 'a queue
+
+is used now. This guarantees that the empty value can be generated
+without anomalies.
+
+For details see:
+
+ http://caml.inria.fr/FAQ/FAQ_EXPERT-eng.html#variables_de_types_faibles
+
+This change allowed e.g. the translation of "PhysicstsQueue". Of course,
+you have to use "empty ()" to get the empty value of queues now.
+
+---------------------------------------------------------------------------
+
+Enjoy the data structures!
+
+Vienna, April 9, 1999
+Markus Mottl (markus.mottl@gmail.com)
View
@@ -0,0 +1,52 @@
+This directory contains the Standard ML source code from
+
+ Purely Functional Data Structures
+ Chris Okasaki
+ Cambridge University Press, 1998
+
+The code is organized into files according to chapter, from "chp2.sml" to
+"chp11.sml". Each file is self-contained, except for a few miscellaneous
+definitions in "base.sml".
+
+The code in the book assumes two non-standard language extensions: support for
+lazy evaluation and support for polymorphic recursion. I have modified the
+on-line code to work around the lack of polymorphic recursion, but I have
+made only minor changes regarding lazy evaluation. IN PARTICULAR, IF YOU
+COMPILE THE CODE "AS IS", IT WILL NOT USE LAZY EVALUATION, AND SO WILL NOT
+ACHIEVE THE RUNNING TIMES CLAIMED IN THE BOOK.
+
+In the book, I assumed that lazy evaluation was supported in the language with
+a $ operator: "$ exp" would create a suspension for the expression "exp", and
+matching that suspension against a pattern of the form "$ pat" would evaluate
+and memoize the suspension. In the on-line code, I simulate this with the
+following definition in "base.sml":
+
+ datatype 'a susp = $ of 'a
+
+But, of course, this $ constructor is not lazy!
+
+There are two further differences related to lazy evaluation. First, the
+code in the book assumes that $ parses with a lower precedence than an ordinary
+constructor. Therefore, in the on-line code, I have replaced some occurrences
+of "$ exp" with "$ (exp)". Second, the code in the book assumes the
+ability to write lazy functions using a special "fun lazy" syntax. In the
+on-line code, I have eliminated dependence on this form.
+
+Note that Standard ML of New Jersey now supports lazy evaluation using a
+similar, but not quite identical, syntax. Updating the on-line code
+to use their syntax requires the following changes:
+
+ - replace each occurrence of
+ val s = $ (exp)
+ with
+ val lazy s = $ (exp)
+
+ - replace each remaining occurrence of
+ ... $ (exp) ...
+ with
+ let val lazy s = $ (exp)
+ in ... s ... end
+
+
+Chris Okasaki
+cdo@cs.columbia.edu
View
@@ -0,0 +1 @@
+release-1-0-6
View
@@ -0,0 +1,130 @@
+(*
+ Original source code in SML from:
+
+ Purely Functional Data Structures
+ Chris Okasaki
+ Cambridge University Press, 1998
+ Copyright (c) 1998 Cambridge University Press
+
+ Translation from SML to OCAML (this file):
+
+ Copyright (C) 1999, 2000, 2001 Markus Mottl
+ email: markus.mottl@gmail.com
+ www: http://www.ocaml.info
+
+ Unless this violates copyrights of the original sources, the following
+ licence applies to this file:
+
+ This source code is free software; you can redistribute it and/or
+ modify it without any restrictions. It is distributed in the hope
+ that it will be useful, but WITHOUT ANY WARRANTY.
+*)
+
+(***********************************************************************)
+(* Chapter 2 *)
+(***********************************************************************)
+
+exception Empty
+exception Subscript
+
+
+module type STACK = sig
+ type 'a stack
+
+ val empty : 'a stack
+ val is_empty : 'a stack -> bool
+ val cons : 'a -> 'a stack -> 'a stack
+ val head : 'a stack -> 'a (* raises Empty if stack is empty *)
+ val tail : 'a stack -> 'a stack (* raises Empty if stack is empty *)
+end
+
+
+module ListStack : STACK = struct
+ type 'a stack = 'a list
+
+ let empty = []
+ let is_empty s = s = []
+ let cons x s = x :: s
+ let head = function [] -> raise Empty | h :: _ -> h
+ let tail = function [] -> raise Empty | _ :: t -> t
+end
+
+
+module CustomStack : STACK = struct
+ type 'a stack = Nil | Cons of 'a * 'a stack
+
+ let cons x s = Cons (x, s)
+ let empty = Nil
+
+ let is_empty s = s = Nil
+ let head = function Nil -> raise Empty | Cons (x, _) -> x
+ let tail = function Nil -> raise Empty | Cons (_, s) -> s
+
+ let rec (++) xs ys =
+ if is_empty xs then ys
+ else cons (head xs) (tail xs ++ ys)
+end
+
+
+let rec (++) xs ys = match xs with
+ | [] -> ys
+ | xh :: xt -> xh :: (xt ++ ys)
+
+let rec update lst i y = match lst, i with
+ | [], _ -> raise Subscript
+ | x :: xs, 0 -> y :: xs
+ | x :: xs, _ -> x :: update xs (i - 1) y
+
+
+module type SET = sig
+ type elem
+ type set
+
+ val empty : set
+ val insert : elem -> set -> set
+ val member : elem -> set -> bool
+end
+
+
+(* A totally ordered type and its comparison functions *)
+module type ORDERED = sig
+ type t
+
+ val eq : t -> t -> bool
+ val lt : t -> t -> bool
+ val leq : t -> t -> bool
+end
+
+
+module UnbalancedSet (Element : ORDERED) : (SET with type elem = Element.t) =
+struct
+ type elem = Element.t
+ type tree = E | T of tree * elem * tree
+ type set = tree
+
+ let empty = E
+
+ let rec member x = function
+ | E -> false
+ | T (a, y, b) ->
+ if Element.lt x y then member x a
+ else if Element.lt y x then member x b
+ else true
+
+ let rec insert x = function
+ | E -> T (E, x, E)
+ | T (a, y, b) as s ->
+ if Element.lt x y then T (insert x a, y, b)
+ else if Element.lt y x then T (a, y, insert x b)
+ else s
+end
+
+
+module type FINITE_MAP = sig
+ type key
+ type 'a map
+
+ val empty : 'a map
+ val bind : key -> 'a -> 'a map -> 'a map
+ val lookup : key -> 'a map -> 'a (* raise Not_found if key is not found *)
+end
Oops, something went wrong.

0 comments on commit fbf915a

Please sign in to comment.