[MLton-user]
Generating dummy values for tying cycles, serialization
Vesa Karvonen
vesa.karvonen at cs.helsinki.fi
Mon Aug 28 22:50:13 PDT 2006
In
Type-Specialized Serialization with Sharing,
Martin Elsman,
University of Copenhagen,
IT University Technical Report TR-2004-43, 2004.
http://mlton.org/References#Elsman04
a type-indexed serialization library is described that has a combinator
refCyc for serializing (possibly cyclic) references. refCyc has the
specification
val refCyc : 'a -> 'a pu -> 'a ref pu
which means that the user is responsible for passing a dummy value (the
first parameter) to refCyc for tying cycles. (Read the report for further
details.) In this very brief note (few words, more code) I'll show how to
generate dummy type-indexed values.
(The end of this message contains some utilities. Full code is included
in this message.)
First a generic signature for "structural" type-indexed values:
signature STRUCTURAL_TYPE =
sig
type 'a t
val iso : ('a, 'b) emb -> 'b t -> 'a t
val * : 'a t * 'b t -> ('a, 'b) product t
val + : 'a t * 'b t -> ('a, 'b) sum t
val Y : 'a t Fix.t
val --> : 'a t * 'b t -> ('a -> 'b) t
val exn : exn t
val regExn : (exn -> ('a * 'a t) option) effect
val array : 'a t -> 'a array t
val list : 'a t -> 'a list t
val refc : 'a t -> 'a ref t
val vector : 'a t -> 'a vector t
val bool : bool t
val char : char t
val int : int t
val real : real t
val string : string t
val unit : unit t
val word : word t
end
Then the signature for the type-indexed dummy values:
signature DUMMY =
sig
include STRUCTURAL_TYPE
val dummy : 'a t -> 'a
val prj : ('b -> 'a) -> 'b t -> 'a t
end
The implementation is mostly straightforward (see the comments for some
fine points):
structure Dummy :> DUMMY =
struct
type 'a t = 'a option
val dummy = valOf
fun prj b2a = Option.map b2a
fun iso (_, p) = prj p
(* When computing dummy products and sums we propagate definedness: *)
fun a * b = case a & b of
SOME a & SOME b => SOME (a & b)
| _ => NONE
fun a + b = case a of
SOME a => SOME (INL a)
| NONE => Option.map INR b
fun Y ? = Fix.pure (const (NONE, id)) ?
(* We use the more general Fixpoint framework (by Stephen Weeks)
* that allows functional fixpoints. Note that the initial value is
* undefined.
*)
fun _ --> _ = SOME (fail (Fail "Dummy.-->"))
(* To define a function (for example), no other dummy values are
* needed.
*)
val exn = SOME Empty
val regExn = ignore
fun array _ = SOME (Array.tabulate (0, undefined))
fun list _ = SOME []
fun refc a = Option.map ref a
fun vector _ = SOME (Vector.tabulate (0, undefined))
val bool = SOME false
val char = SOME #"\000"
val int = SOME 1
val real = SOME 0.0
val string = SOME ""
val unit = SOME ()
val word = SOME 0w0
end
Here is an example:
datatype 'a tree = B of 'a tree * 'a * 'a tree | N
fun tree a =
let
open Fix Dummy
in
fix Y (fn tree_a =>
iso (fn B (l, x, r) => INL (l & x & r) | N => INR (),
fn INL (l & x & r) => B (l, x, r) | INR () => N)
(tree_a * a * tree_a + unit))
end
val N =
let
open Dummy
in
dummy (tree int)
end
Using this technique, it should be possible to build a serialization
library that doesn't require the user to specify a dummy value for
serializing references.
The necessary utilities and the Fixpoint framework are below.
-Vesa Karvonen
(* Operator precedence table *)
infix 8 * / div mod (* +1 from Basis Library *)
infix 7 + - ^ (* +1 from Basis Library *)
infixr 6 :: @ (* +1 from Basis Library *)
infix 5 = <> > >= < <= (* +1 from Basis Library *)
infix 4 <\ \>
infixr 4 </ />
infix 3 o
infix 2 >|
infixr 2 |<
infix 1 := (* -2 from Basis Library *)
infix 0 before &
infixr 0 -->
(* Some basic combinators *)
fun const x _ = x
fun cross (f, g) (x, y) = (f x, g y)
fun curry f x y = f (x, y)
fun fail e _ = raise e
fun id x = x
fun undefined _ = raise Fail "undefined"
fun fst (a, _) = a
fun snd (_, b) = b
(* Product type *)
datatype ('a, 'b) product = & of 'a * 'b
(* Sum type *)
datatype ('a, 'b) sum = INL of 'a | INR of 'b
(* Some type shorthands *)
type 'a sq = 'a * 'a
type 'a uop = 'a -> 'a
type 'a fix = 'a uop -> 'a
type 'a thunk = unit -> 'a
type 'a effect = 'a -> unit
type 'a compare = 'a sq -> order
type ('a, 'b) emb = ('a -> 'b) * ('b -> 'a)
(* Infixing, sectioning, and application operators *)
fun x <\ f = fn y => f (x, y)
fun f \> y = f y
fun f /> y = fn x => f (x, y)
fun x </ f = f x
(* Piping operators *)
val op>| = op</
val op|< = op\>
(* Fixpoint framework with the "pure" combinator *)
signature FIX =
sig
type 'a t1
type 'a t2
type 'a t = 'a t1 -> 'a t2
exception Fix
val fix : 'a t -> 'a fix
val pure : ('a * 'a uop) thunk -> 'a t
val tier : ('a * 'a effect) thunk -> 'a t
val iso : ('a, 'b) emb -> 'b t -> 'a t
val ^ : 'a t * 'b t -> ('a, 'b) product t
end
structure Fix :> FIX =
struct
type 'a t1 = unit
type 'a t2 = 'a * 'a uop
type 'a t = 'a t1 -> 'a t2
exception Fix
fun fix a f =
let
val (a, ta) = a ()
in
ta (f a)
end
val pure = id
fun tier th () =
let
val (a, ta) = th ()
in
(a, const a o ta)
end
fun iso (a2b, b2a) b () =
let
val (b, tb) = b ()
in
(b2a b, b2a o tb o a2b)
end
fun (a ^ b) () =
let
val (a, ta) = a ()
val (b, tb) = b ()
in
(a & b, fn a & b => ta a & tb b)
end
end
More information about the MLton-user
mailing list