Standard ML is an eager (or strict) language, not a lazy language. However, it is easy to delay evaluation of an expression in SML by creating a thunk, which is a nullary function. In SML, a thunk is written fn () => e. Another essential feature of laziness is memoization, meaning that once a suspended argument is evaluated, subsequent references look up the value. We can express this in SML with a function that maps a thunk to a memoized thunk.
signature LAZY = sig val lazy: (unit -> 'a) -> unit -> 'a end
This is easy to implement in SML.
structure Lazy: LAZY = struct fun lazy (th: unit -> 'a): unit -> 'a = let val r: 'a option ref = ref NONE in fn () => case !r of NONE => let val a = th () val () = r := SOME a in a end | SOME a => a end end