[MLton-user] Fixpoints
Stephen Weeks
sweeks@sweeks.com
Tue, 1 Aug 2006 12:48:16 -0700
I was reading through
http://mlton.org/Fixpoints
and had an idea for simplifying things. The idea is to hide the type
of the slot used to construct fixpoints underneath a closure, so that
it doesn't appear in the type of tiers. As a minor change, I think it
is also cleaner to include the thunk used to work around the value
restriction directly in the type of tiers. Those changes and some
other minor cleanup lead to the following signature.
signature FIX =
sig
type 'a u
type 'a t = 'a u thunk
exception Fix
val ^ : 'a t * 'b t -> ('a, 'b) product t
val fix: 'a t * ('a -> 'a) -> 'a
val iso: 'a t * ('a, 'b) emb -> 'b t
val tier: ('a * ('a -> 'a)) thunk -> 'a t
end
Now, a tier is a thunk that creates the slot and returns an initial
value for the knot paired with a function that ties the knot and
returns it. But, the actual slot type is completely hidden in the
closures.
Here's the complete code.
--------------------------------------------------------------------------------
datatype ('a, 'b) product = & of 'a * 'b
infix &
type 'a thunk = unit -> 'a
type ('a, 'b) emb = ('a -> 'b) * ('b -> 'a)
signature FIX =
sig
type 'a u
type 'a t = 'a u thunk
exception Fix
val ^ : 'a t * 'b t -> ('a, 'b) product t
val fix: 'a t * ('a -> 'a) -> 'a
val iso: 'a t * ('a, 'b) emb -> 'b t
val tier: ('a * ('a -> 'a)) thunk -> 'a t
end
structure Fix :> FIX =
struct
datatype 'a u = U of ('a * ('a -> 'a))
type 'a t = 'a u thunk
exception Fix
fun tier t = U o t
fun fix (t, f) =
let
val U (a, a') = t ()
in
a' (f a)
end
fun a ^ b = fn () =>
let
val U (a, a') = a ()
val U (b, b') = b ()
in
U (a & b, fn a & b => a' a & b' b)
end
fun iso (a, (a2b, b2a)) () =
let
val U (a, a') = a ()
in
U (a2b a, a2b o a' o b2a)
end
end
structure Fn :>
sig
val T : ('a -> 'b) Fix.t
end =
struct
fun T ? = Fix.tier (fn () =>
let
val r = ref (fn _ => raise Fix.Fix)
fun f a = !r a
in
(f, fn f' => (r := f'; f))
end) ?
end
val isEven & isOdd =
Fix.fix
(let open Fix Fn in T^T end,
fn isEven & isOdd =>
(fn 0w0 => true
| 0w1 => false
| n => isOdd (n-0w1)) &
(fn 0w0 => false
| 0w1 => true
| n => isEven (n-0w1)))
structure Promise :>
sig
type 'a t
val lazy : 'a thunk -> 'a t
val force : 'a t -> 'a
val T : 'a t Fix.t
end = struct
datatype 'a t' = EXN of exn
| THUNK of 'a thunk
| VALUE of 'a
withtype 'a t = 'a t' ref
fun lazy f = ref (THUNK f)
fun force t =
case !t of
EXN e => raise e
| THUNK f =>
(t := VALUE (f ())
handle e => t := EXN e
; force t)
| VALUE v => v
fun T ? = Fix.tier (fn () =>
let
val p = lazy (fn () => raise Fix.Fix)
in
(p, fn x => (p := !x; p))
end) ?
end
structure Stream :>
sig
type 'a t
val cons: 'a * 'a t -> 'a t
val get: 'a t -> ('a * 'a t) option
val T: 'a t Fix.t
end =
struct
datatype 'a t = IN of ('a * 'a t) option Promise.t
fun cons (x, xs) = IN (Promise.lazy (fn () => SOME (x, xs)))
fun get (IN p) = Promise.force p
fun T ? = Fix.iso (Promise.T, (IN, fn IN p => p)) ?
end
val ones =
let open Fix Stream
in fix (T, fn ones => cons (1, ones))
end