Wednesday, October 10, 2012

Combinators over Records and Unions

In the previous post, I discussed designing combinator libraries that compose some property over unions. It is only fitting to throw records in the mix.

type U =
    | A of int
    | B of float
    | C of string

let UFormat =
    (
        UnionCase A IntFormat <<
        UnionCase B FloatFormat <<
        UnionCase C StringFormat
    )
    |> Union (fun a b c x ->
        match x with
        | A x -> a x
        | B x -> b x
        | C x -> c x)

type R =
    {
        A : int
        B : float
        C : string
    }

let RFormat : Format<R> =
    (
        RecordField (fun r -> r.A) IntFormat <<
        RecordField (fun r -> r.B) FloatFormat <<
        RecordField (fun r -> r.C) StringFormat
    )
    |> Record (fun a b c -> { A = a; B = b; C = c })

With some simplifications, here is the code:

open System.IO
type Format<'T> =
{
Read : BinaryReader -> 'T
Write : BinaryWriter -> 'T -> unit
}
(* Unions *)
type UnionPart<'X,'U> =
{
R : list<BinaryReader -> 'U>
W : 'X -> 'U -> BinaryWriter -> unit
}
let UnionCase (ctor: 'C -> 'U) (fmt: Format<'C>)
(part: UnionPart<'X,'U>) : UnionPart<('C -> unit) -> 'X,'U> =
let tag = char part.R.Length
let write (w: BinaryWriter) x =
w.Write(tag)
fmt.Write w x
{
R = (fmt.Read >> ctor) :: part.R
W = fun f u w -> part.W (f (write w)) u w
}
let private unionEnd<'U> : UnionPart<('U -> unit),'U> =
{
R = []
W = fun f u w -> f u
}
let Union proof f =
let part = f unionEnd
let rs = Array.rev (List.toArray part.R)
{
Read = fun r ->
let tag = int (r.ReadChar())
rs.[tag] r
Write = fun w x -> part.W proof x w
}
(* Records *)
type RecordPart<'X,'R> =
{
R : 'X -> BinaryReader -> 'R
W : list<BinaryWriter -> 'R -> unit>
}
let RecordField<'F,'U,'X> (proj: 'U -> 'F) (fmt: Format<'F>) (part: RecordPart<'X,'U>) : RecordPart<'F -> 'X, 'U> =
{
R = fun x r -> part.R (x (fmt.Read(r))) r
W = (fun w x -> fmt.Write w (proj x)) :: part.W
}
let private recordEnd<'T> : RecordPart<'T,'T> =
{
R = fun r _ -> r
W = []
}
let Record proof f =
let x = f recordEnd
let ws = List.toArray x.W
{
Read = x.R proof
Write = fun w x -> for f in ws do f w x
}
(* Scalars *)
let IntFormat : Format<int> =
{
Read = fun r -> r.ReadInt32()
Write = fun w x -> w.Write(x)
}
let FloatFormat : Format<float> =
{
Read = fun r -> r.ReadDouble()
Write = fun w x -> w.Write(x)
}
let StringFormat : Format<string> =
{
Read = fun r -> r.ReadString()
Write = fun w x -> w.Write(x)
}

1 comment:

  1. Hotel and Casino Las Vegas Map & Floor Plans - MapYRO
    A Casino Las 광양 출장샵 Vegas Floor Plan. 경상북도 출장샵 1. 1. Mapyro. 문경 출장마사지 3. Hotel 원주 출장샵 and 경산 출장안마 Casino Las Vegas, NV (South Tower)

    ReplyDelete