Created
June 14, 2012 04:51
-
-
Save einblicker/2928049 to your computer and use it in GitHub Desktop.
Expression Problem in F#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* | |
type IFoo = | |
abstract M1 : unit -> int | |
abstract M2 : unit -> int | |
このインターフェースの一部だけを実装した抽象クラス | |
[<AbstractClass>] | |
type Bar() = | |
interface IFoo with | |
override x.M1() = 0 | |
が作れないのでF#でthisをプロパティにするアプローチは微妙。 | |
恐らく素直にhttp://www.daimi.au.dk/~madst/ecoop04/main.pdfの方法でやるべき。 | |
ただしgenericsの共変性が使えないので少し不便かも。 | |
*) | |
module Base = | |
type IBaseNode<'V, 'N when 'V :> IBaseVisitor<'V, 'N> and 'N :> IBaseNode<'V, 'N>> = | |
//abstract This : 'V //本当はこうしたい | |
abstract Accept : 'V -> unit | |
and IBaseVisitor<'V, 'N when 'V :> IBaseVisitor<'V, 'N> and 'N :> IBaseNode<'V, 'N>> = | |
abstract Visit : AddNode<'V, 'N> -> unit | |
abstract Visit : SubNode<'V, 'N> -> unit | |
abstract Visit : NumberNode<'V, 'N> -> unit | |
and [<AbstractClass>] AddNode<'V, 'N when 'V :> IBaseVisitor<'V, 'N> and 'N :> IBaseNode<'V, 'N>>(l : IBaseNode<'V, 'N>, r : IBaseNode<'V, 'N>) = | |
member this.Left = l | |
member this.Right = r | |
interface IBaseNode<'V, 'N> with | |
member this.Accept(visitor) = visitor.Visit(this) | |
and [<AbstractClass>] SubNode<'V, 'N when 'V :> IBaseVisitor<'V, 'N> and 'N :> IBaseNode<'V, 'N>>(l : IBaseNode<'V, 'N>, r : IBaseNode<'V, 'N>) = | |
member this.Left = l | |
member this.Right = r | |
interface IBaseNode<'V, 'N> with | |
member this.Accept(visitor) = visitor.Visit(this) | |
and [<AbstractClass>] NumberNode<'V, 'N when 'V :> IBaseVisitor<'V, 'N> and 'N :> IBaseNode<'V, 'N>>(value) = | |
member this.GetValue = value | |
interface IBaseNode<'V, 'N> with | |
member this.Accept(visitor) = visitor.Visit(this) | |
type Node = | |
inherit IBaseNode<Visitor, Node> | |
and Visitor = | |
inherit IBaseVisitor<Visitor, Node> | |
type Add(l, r) = | |
inherit AddNode<Visitor, Node>(l, r) | |
interface Node | |
type Sub(l, r) = | |
inherit SubNode<Visitor, Node>(l, r) | |
interface Node | |
type Num(value) = | |
inherit NumberNode<Visitor, Node>(value) | |
interface Node | |
//EvalをExtで再利用するために型パラメータを付けるべき | |
//F#だとinterfaceの一部だけを実装した抽象クラスが作れないので無理かも | |
type Eval() = | |
let mutable value = 0 | |
member this.Result = value | |
interface Visitor with | |
override this.Visit(node : AddNode<Visitor, Node>) = | |
node.Left.Accept(this) | |
let val0 = value | |
node.Right.Accept(this) | |
let val1 = value | |
value <- val0 + val1 | |
override this.Visit(node : SubNode<Visitor, Node>) = | |
node.Left.Accept(this) | |
let val0 = value | |
node.Right.Accept(this) | |
let val1 = value | |
value <- val0 - val1 | |
override this.Visit(node : NumberNode<Visitor, Node>) = | |
value <- node.GetValue | |
module Ext = | |
open Base | |
type IExtVisitor<'V, 'N when 'V :> IExtVisitor<'V, 'N> and 'N :> IBaseNode<'V, 'N>> = | |
inherit IBaseVisitor<'V, 'N> | |
abstract Visit : MulNode<'V, 'N> -> unit | |
and [<AbstractClass>] MulNode<'V, 'N when 'V :> IExtVisitor<'V, 'N> and 'N :> IBaseNode<'V, 'N>>(l : IBaseNode<'V, 'N>, r : IBaseNode<'V, 'N>) = | |
member this.Left = l | |
member this.Right = r | |
interface IBaseNode<'V, 'N> with | |
member this.Accept(visitor) = visitor.Visit(this) | |
type Node = | |
inherit IBaseNode<Visitor, Node> | |
and Visitor = | |
inherit IExtVisitor<Visitor, Node> | |
type Add(l, r) = | |
inherit AddNode<Visitor, Node>(l, r) | |
interface Node | |
type Sub(l, r) = | |
inherit SubNode<Visitor, Node>(l, r) | |
interface Node | |
type Num(value) = | |
inherit NumberNode<Visitor, Node>(value) | |
interface Node | |
type Mul(l, r) = | |
inherit MulNode<Visitor, Node>(l, r) | |
interface Node | |
type Show() = | |
let mutable str = "" | |
member this.Result = str | |
interface Visitor with | |
override this.Visit(node : AddNode<Visitor, Node>) = | |
node.Left.Accept(this) | |
let val0 = str | |
node.Right.Accept(this) | |
let val1 = str | |
str <- "(" + val0 + " + " + val1 + ")" | |
override this.Visit(node : SubNode<Visitor, Node>) = | |
node.Left.Accept(this) | |
let val0 = str | |
node.Right.Accept(this) | |
let val1 = str | |
str <- "(" + val0 + " - " + val1 + ")" | |
override this.Visit(node : NumberNode<Visitor, Node>) = | |
str <- string(node.GetValue) | |
override this.Visit(node : MulNode<Visitor, Node>) = | |
node.Left.Accept(this) | |
let val0 = str | |
node.Right.Accept(this) | |
let val1 = str | |
str <- "(" + val0 + " * " + val1 + ")" | |
open Base | |
let test1 () = | |
let ast = Sub(Add(Num(1), Num(2)), Add(Num(3), Num(4))) :> Node | |
let eval = Eval() | |
ast.Accept(eval) | |
printfn "%A" eval.Result | |
test1() | |
open Ext | |
let test2 () = | |
let ast = Sub(Add(Num(1), Num(2)), Mul(Num(3), Num(4))) :> Node | |
let show = Show() | |
ast.Accept(show) | |
printfn "%A" show.Result | |
test2() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment