Skip to content

Instantly share code, notes, and snippets.

@hodzanassredin
Created March 9, 2016 15:08
Show Gist options
  • Save hodzanassredin/40c63c286466bff38516 to your computer and use it in GitHub Desktop.
Save hodzanassredin/40c63c286466bff38516 to your computer and use it in GitHub Desktop.
solving expression problem in fsharp with object algebras
type ExpAlg<'a> =
abstract member lit: int -> 'a
abstract member Add: 'a -> 'a -> 'a
type Algebra<'alg,'a> = 'alg -> 'a
let lit i (alg:ExpAlg<'a>) = alg.lit i
let add a b (alg:ExpAlg<'a>) = alg.Add a b
type AlgebraBuilder() =
member inline x.Return(v) : Algebra<'alg,'r> = fun r -> v
member inline x.ReturnFrom(v) : Algebra<'alg,'r> = v
member inline x.Bind(rm1:Algebra<'alg,'r>, f:'r -> Algebra<'alg,'r2>) : Algebra<'alg,'r2> =
fun a -> let r = rm1 a
f r a
let algebra = AlgebraBuilder()
let e1() = algebra{
let! a = lit 1
let! b = lit 2
let! c = lit 3
let! bc = add b c
return! add a bc
}
let e1b (alg:ExpAlg<'a>) =
alg.Add (alg.lit 1) (alg.Add (alg.lit(1)) (alg.lit(1)))
type Eval =
abstract member eval: unit -> int
type EvalExp () =
interface ExpAlg<Eval> with
member this.Add x y =
{new Eval with member this.eval() = x.eval() + y.eval() }
member this.lit i =
{new Eval with member this.eval() = i }
printfn "eval e1 %A" <| (e1 () (EvalExp())).eval()
type MulAlg<'a> =
inherit ExpAlg<'a>
abstract member Mul: 'a -> 'a -> 'a
let mul a b (alg:MulAlg<'a>) = alg.Mul a b
let e2() = algebra{
let! a = lit 1
let! b = lit 2
let! c = lit 3
let! bc = add b c
return! mul a bc
}
type EvalMulExp () =
inherit EvalExp()
interface MulAlg<Eval> with
member this.Mul x y =
{new Eval with member this.eval() = x.eval() * y.eval() }
printfn "eval e2 %A" <| (e2 () (EvalMulExp())).eval()
type View =
abstract member view: unit -> string
type ViewExp () =
interface ExpAlg<View> with
member this.Add x y =
{new View with member this.view() = sprintf "(%s + %s)" <| x.view() <| y.view() }
member this.lit i =
{new View with member this.view() = i.ToString() }
type ViewMulExp () =
inherit ViewExp()
interface MulAlg<View> with
member this.Mul x y =
{new View with member this.view() = sprintf "(%s * %s)" <| x.view() <| y.view() }
printfn "view e1 %A" <| (e1 () (ViewExp())).view()
printfn "view e2 %A" <| (e2 () (ViewMulExp())).view()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment