Laziness is a corner stone in the book Purely Functional Data Structures, but it is not clearly described how he obtains it, at least to me. I thought I only needed to write:
datatype 'a susp = $ of 'a
fun force ($x) = x
fun plus (x, y) = $case (x, y) of ($m, $n) => m + n
But then I get the error:
- use "ch4.sml";;
[opening ch4.sml]
ch4.sml:3.20 Error: syntax error: inserting ORELSE
[unexpected exception: Compile]
uncaught exception Compile [Compile: "syntax error"]
raised at: ../compiler/Parse/main/smlfile.sml:19.24-19.46
../compiler/TopLevel/interact/evalloop.sml:45.54
../compiler/TopLevel/interact/evalloop.sml:306.20-306.23
../compiler/TopLevel/interact/interact.sml:65.13-65.16
I tried modifying the function to
fun plus (x, y) = $(print "Evaluating...\n"; force x + force y)
But calling it with plus ($4, $5)
evaluated it and didn't memoize it because it returns $ 9
instead of $ plus(force $4, force $5)
and it printed Evaluating...
both times.
- plus ($4, $5);;
Evaluating...
val it = $ 9 : int susp
- plus ($4, $5);;
Evaluating...
val it = $ 9 : int susp
I'd also like to obtain the keyword lazy
, but I'm not sure whether SML New Jersey supports this, whether it was implemented by Chris Okasaki, or that it's manually desugared.
The keyword is highlighted in my editor but when writing
fun lazy plus ($x, $y) = $ (x + y)
I get that lazy
is the function taking two parameters plus
and ($x, $y)
as given by the type:
val lazy = fn : 'a -> int susp * int susp -> int susp
My question boils down to How do I obtain laziness and memoization in SML New Jersey?
You need to enable laziness and add some parentheses (the $
in the book has peculiar parsing rules):
Standard ML of New Jersey v110.83 [built: Thu May 31 09:04:19 2018]
- Control.lazysml := true;
[autoloading]
[ ... boring details ...]
[autoloading done]
val it = () : unit
- open Lazy;
[autoloading]
[autoloading done]
opening Lazy
datatype 'a susp = $ of 'a
- fun plus (x, y) = $(case (x, y) of ($m, $n) => m + n);
val plus = fn : int susp * int susp -> int susp
- val x = plus($4, $5);
val x = $$ : int susp
- fun force ($x) = x;
val force = fn : 'a susp -> 'a
- force x;
val it = 9 : int
- fun lazy plus ($x, $y) = $ (x + y);
val plus = fn : int susp * int susp -> int susp
val plus_ = fn : int susp * int susp -> int
Note that this does not memoize plus
.