3

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?

Little Helper
  • 1,870
  • 3
  • 12
  • 20

1 Answers1

5

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.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • This works! The `plus` function is not memoized but the suspension is, e.g., `fun lazy delayed ($x) = $(print "Evaluating...\n"; x)` and then binding it with `val x = delayed ($5)`, and forcing it twice `force x; force x` only prints once. Thank you! However, I don't understand why `fun delayed x = $(case x of ($q) => (print "Evaluating...\n"; q))` doesn't work. When binding it as `val q = delayed ($4)` already prints before being the forced (it is still memoized though). But I'd like to know why the print is not suspended. – Little Helper Jan 20 '20 at 13:23
  • Can you please elaborate on why both `Control.lazysml := true` and `open Lazy` are necessary and what they do? – Little Helper Jan 20 '20 at 13:25
  • The former enables lazy evaluation in the compiler. `open Lazy;` opens the `Lazy` module so you can use unqualified names. (Also, note that `lazy` is not a function.) – molbdnilo Jan 20 '20 at 15:07
  • Do you have any documentation on this? As far as I can tell from the documentation, the [`Control`](https://www.smlnj.org/doc/Compiler/pages/control.html) structure does not seem to include `lazysml`. The `Lazy` structure is also not really documented as far as I can tell, and the link to the `LAZYCONTROL` signature leads nowhere (though some documentation can be found [here](https://flint.cs.yale.edu/cs430/smlnj/doc/Compiler/pages/lazycontrol.html) for some reason). – Danny Apr 18 '23 at 09:38
  • The documentation of the Control structure is pretty miserable, and I can't really remember where I found anything over three years ago. The `lazysml` is there in my 110.99.3 version, though. – molbdnilo Apr 18 '23 at 09:43