è¨èªã®å®è£ ã¯é¢æ°åè¨èªã§ãã¯æ¬å½ã
表é¡ã®æ§ãªãã¨ãã¡ãã£ã¨æ°ã«ãªã£ãã®ã§ãåç¡Î»è¨ç®ã® big step semantics (æ¦ç¥ã¯æ£æ ¼è©ä¾¡)ãå®è£ ãã¾ãããã¾ãè¦ããã«ããã¼ãã¤ã³ã¿ããªã¿ã§ããã
FP ã§Î»è¨ç®ãå®è£ ãã
ã¾ããæ®éã«é¢æ°åè¨èª(OCaml)ã§å®è£
ãã¦ã¿ã¾ããã
- λå¼ã®å㯠t (term)
- λå¼ã«ã¯æ´æ°å®æ°ã¨å æ¸ãããªããã£ãã¨ãã¦è¿½å
- λå¼ãè©ä¾¡ãã㨠value ã«ãªã(è¨ç®æ¢ã¾ããªãå ´åã¯ããããªã)
- value ã«ã¯å¼æ°ãå¾ ã£ã¦ããããªããã£ãããã
open List (** primitives *) type prim = Add | Sub (** terms *) type t = | Int of int | Var of string | App of t * t | Lambda of string * t | Prim of prim (** semantic values *) type value = | VInt of int | Closure of env * string * t | VPrim of prim * int * value list (** Not fully applied primitive *) and env = (string * value) list (** primitive semantics *) let eval_prim prim args = match prim, args with | Add, [VInt i1; VInt i2] -> VInt (i1 + i2) | Sub, [VInt i1; VInt i2] -> VInt (i1 - i2) | _ -> assert false (** big step semantics of terms *) let rec eval env = function | Int n -> VInt n | Var v -> assoc v env | App (t1, t2) -> let v2 = eval env t2 in let v1 = eval env t1 in begin match v1 with | Closure (env, var, t) -> eval ((var,v2)::env) t | VPrim (prim, arity, applied) -> let len = length applied in if arity <= length applied then assert false else if arity = len + 1 then eval_prim prim (rev (v2::applied)) else VPrim (prim, arity, v2 :: applied) | _ -> assert false end | Lambda (v, t) -> Closure (env, v, t) | Prim Add -> VPrim (Add, 2, []) | Prim Sub -> VPrim (Sub, 2, []) (** test *) let () = (* ley y = 2 in let f x = x + y in let y = 100 in f 2 (\y.(\f.(\y.f 2) 100) (\x.x+y)) 2 *) assert (eval [] (App (Lambda ("y", App (Lambda ("f", App (Lambda ("y", App (Var "f", Int 2)), Int 100)), Lambda ("x", App (App (Prim Add, Var "x"), Var "y")))), Int 2)) = VInt 4)
ç¥ã£ã¦ãã人ã«ã¯ããããæ®éã§ããã ã¾ããã¼ã¿åãèãã¦å
¨ã³ã³ã¹ãã©ã¯ã¿ãåæãããããé¢æ°ãæ¸ãã¦ããã
ç¥ããªãï¼ãã¼ã¨ããé¢æ°åè¨èªã®åãç°¡åãªãã¤ã®ã¤ã³ã¿ããªã¿ãé¢æ°åè¨èªã§æ¸ããããããããã®çãã³ã¼ãã§æ¸ãã¾ããã¼ã¨ãããã¨ã ã¨æã£ã¦ãã ããã
ãã¯ã«ãã¹ããã¦ããªããã¨ãããã¯ãã¼ã¸ã£ã¼ã¯ã¯ãã¼ã¸ã£ã¼ã¨ãã¦åãã¦ããã¿ããã ã(let ãªãã§ããããé·ãλå¼æ¸ãã®ã¯æ£ç´ä½ãã¤ãã¦ãããæ³ã«ãªãã¾ãã) eval ãæ«å°¾å帰ã§ãªãããæ°ã«ãªãã¨ãã人ã¯ãèªåã§ç´ãã¦ãã ããã
OO ã§Î»è¨ç®ãå®è£ ãã
ã§ãããããã§ããã¼çãããã¾ãããï¼é¢æ°åè¨èªåãã§ãããï¼ããããï¼ã§ã¯èªåã«å¯¾ãã¦ã説å¾åç¡ãã®ã§ãããããä»åº¦ã¯åãç©ã OO ã§æ¸ãã¦ã¿ã¾ããæ¬è«ã®ç®ç㯠FP 㨠OO ã¢ããã¼ããæ¯ã¹ããã®ã§ãã®ã§ãããã¦ä»£æ°çãã¼ã¿å(Variant)ã¯ä½¿ã£ããè² ãããªã®ã§ä½¿ãã¾ãããã§ããã ãã¯ã©ã¹ã§å®ç¾ãã¾ãã
open List (** interfaces *) class virtual value = object end class virtual prim = object method virtual arity : int method virtual eval : value list -> value end type env = (string * value) list class virtual t = object method virtual eval : env -> value end (** implementations *) (** values *) class vint (n:int) = object inherit value method int = n end class virtual applicable = object inherit value method virtual apply : value -> value end class closure (env:env) (var:string) (t:t) = object inherit applicable method apply v = t#eval ((var,v)::env) end class vprim (prim : prim) (applied : value list) = object inherit applicable method apply v = let len = length applied in let arity = prim#arity in if arity <= len then assert false else if arity = len + 1 then prim#eval (rev (v::applied)) else (new vprim prim (v::applied) :> value) end (** primitives and their semantics *) class prim_add = object inherit prim method arity = 2 method eval = function | [v1; v2] -> (new vint ((Obj.magic v1 : vint)#int + (Obj.magic v2 : vint)#int) :> value) | _ -> assert false end let prim_add = new prim_add class prim_sub = object inherit prim method arity = 2 method eval = function | [v1; v2] -> (new vint ((Obj.magic v1 : vint)#int - (Obj.magic v2 : vint)#int) :> value) | _ -> assert false end let prim_sub = new prim_sub (** terms and their semantics *) class int i = object inherit t method eval _env = (new vint i :> value) end class var v = object inherit t method eval = List.assoc v end class app t1 t2 = object inherit t method eval env = let v2 = t2#eval env in let v1 = t1#eval env in (Obj.magic v1 : applicable)#apply v2 end class lambda var t = object inherit t method eval env = (new closure env var t :> value) end class add = object inherit t method eval _env = (new vprim prim_add [] :> value) end class sub = object inherit t method eval _env = (new vprim prim_sub [] :> value) end (** tools (OCaml requires explicit upcasting, so things go too verbose) *) let var x = (new var x :> t) let int i = (new int i :> t) let app t1 t2 = (new app t1 t2 :> t) let lambda var t = (new lambda var t :> t) let add = (new add :> t) let sub = (new sub :> t) (** test *) let () = assert ((Obj.magic ((app (lambda "y" (app (lambda "f" (app (lambda "y" (app (var "f") (int 2))) (int 100))) (lambda "x" (app (app add (var "x")) (var "y"))))) (int 2))#eval []) : vint)#int = 4)
OCaml 㯠upcast ãæ示ããªããã°ãªãã (e :> t)ããã㦠downcast ã¯ä¸å¯ãªã®ã§ (Obj.magic e : t) ã 使ã£ã¦ç¡çããæ¸ãã¦ãã¾ãããããã¯åçãªã¯ã©ã¹æ¤æ»ã³ã¼ãã¨æã£ã¦ããã£ã¦è¯ãã§ãã (å®éã«ã¯æ¤æ»ãã¾ããã)
ã¾ãåºåºã¯ã©ã¹ãå®ç¾©ãã¦å
¨ã¤ã³ã¿ã¼ãã§ã¼ã¹ãæ¸ããããããåãµãã¯ã©ã¹ãä¸ã¤ã¥ã¤æ¸ãã¦ããã FPã§ã®åãOOã§ã®åºåºã¯ã©ã¹ãFPã§ã®ã³ã³ã¹ãã©ã¯ã¿ããµãã¯ã©ã¹ã¨å¯¾å¿ãã¾ãã å¤ãé©ç¨ã§ããå¤ã¨ãã¦ãclosure 㨠vprim ãããã®ã§ããããã®ã¹ã¼ãã¼ã¯ã©ã¹ã¨ã㦠applicable ã¨ãã ã¤ã³ã¿ã¼ãã§ã¼ã¹(ä»®æ³ã¯ã©ã¹/æ½è±¡ã¯ã©ã¹)ã value 㨠closure, vprim ã®éã«å®ç¾©ãã¾ããã
é·ãã§ãã⦠FPçã¨æ¯ã¹ã¦ 35% ä½é·ãã§ãã
æ¸ãã®ã¯å®éè¦å´ãã¾ãããã¯ã©ã¹é層ãã©ããããã®ãã¨ããã©ãã¾ã§ method ã«ãããæ©ã¿ã¾ãããã幸éã«ãã ããããã£ããã¯ã©ã¹ã«åãè¾¼ãã¾ããããã¡ããæ
£ãã¦ãªãã ãããããã¾ãããFP ã¢ããã¼ãã代æ°çãã¼ã¿åã«æ
£ãã¦ãªã人ã«ã¨ã£ã¦ã¯æ¸ãã®ã¯ä¸è¦å´ã ã¨æ³åãã¾ãã
ç§ã¯ä¸¡æ¹ç¥ã£ã¦ãã人ã«ã¨ã£ã¦ã¯ã©ãèãã¦ã代æ°çãã¼ã¿åã®æ¹ãå¤ããããã¨æãã¾ããããã¡ããâ»å人ã®ææ³ã§ããλè¨ç®ã®ææ³ãã»ãã³ãã£ã¯ã¹ã®å®ç¾©èªä½ã代æ°çãã¼ã¿åã¨ã»ã¨ãã©å¤è¦ãåããªã®ã§ FP ã¢ããã¼ãã§ã¯åçµããã ããªã®ã§ç°¡åãªã¯ããªã®ã§ããããã¡ããããã¯é¢æ°å好ããªäººã®â»å人ã®ææ³ã§ãã
OCaml ã® OO ã¯ãªã«ã·ã¤ã¨æãããæ¹ãããã¨æãã¾ãã®ã§ Ruby ã§ããã¯ã¿ã¤ãã³ã°ããµãã ãã«ä½¿ã£ã¦æ¸ãã¦ã¿ã¾ãããç§ã®å Ruby ããã°ã©ã ã§ã!:
# values class Vint def initialize(i) @int = i end attr_reader :int end class Closure def initialize(env, v, t) @env = env @var = v @term = t end def apply(v) env2 = @env.clone env2[@var] = v @term.eval(env2) end end class Vprim def initialize(prim, applied) @prim = prim @applied = applied end def apply(v) len = @applied.size arity = @prim.arity if arity <= len then raise else if arity == len + 1 then @prim.prim_eval(@applied + [v]) else Vprim.new(@prim, @applied + [v]) end end end end class Prim_add def initialize() @arity = 2 end attr_reader :arity def prim_eval(vs) if vs.size == 2 then Vint.new(vs[0].int + vs[1].int) else raise end end end prim_add = Prim_add.new() puts prim_add.prim_eval([Vint.new(1), Vint.new(2)]).int class Prim_sub def initialize() @arity = 2 end attr_reader :arity def prim_eval(vs) if vs.size == 2 then Vint.new(vs[0].int - vs[1].int) else raise end end end # terms class Int def initialize(i) @i = i end def eval(_env) Vint.new(@i) end end class Var def initialize(v) @var = v end def eval(env) env[@var] end end class App def initialize(t1, t2) @t1 = t1 @t2 = t2 end def eval(env) v2 = @t2.eval(env) v1 = @t1.eval(env) v1.apply(v2) end end class Lambda def initialize(var, t) @var = var @term = t end def eval(env) Closure.new(env, @var, @term) end end class Add def eval(_env) Vprim.new(Prim_add.new, []) end end class Sub def eval(_env) Vprim.new(Prim_sub.new, []) end end # tools def var(v) Var.new(v) end def int(i) Int.new(i) end def app(t1, t2) App.new(t1,t2) end def lambda(v, t) Lambda.new(v,t) end add = Add.new() sub = Sub.new() test = app(lambda("y", app(lambda("f", app(lambda("y", app(var("f"), int(2))), int(100))), lambda("x", (app(app(add, var("x")), var("y")))))), int(2)) puts test.eval(Hash.new).int
Ruby ã§ã¯ cons list ãããå¤ããªãã£ãã®ã§ Hash ã clone ãã¦ãã¾ããã¾ããããããã¨ã¯å¤§ä½æ¸ãã¦ãã¾ãã ãã¤ãæ°ã§ OO ã«ãã¦åãæ¸ããã¾ãã£ã OCaml ã³ã¼ãã® 9å²ä½ã§ãããæã£ããã縮ã¿ã¾ãããã (è¡æ°ã§æ¯ã¹ãã»ã©å¿ã®çãç·ã§ã¯ããã¾ãããç§ã¯) ã¾ãããã£ã¨çããªããã§ããããã©ãOCaml ã® OO ã¢ããã¼ãã¯åãããããåºã¦ãã¦èªã¿ã«ããã£ãã®ã§æ¸ãã¦ã¿ãã ãã§ãè¨èªdisããç®çã§ã¯ãªããã§ãã®è¾ºã¯ã©ãã§ãããã§ãã åçãªãã§ãã¯ã¯æ示ãããåçãªã¯ã©ã¹ãã§ãã¯(OCaml çã§ã¯ (Obj.magic e : t) ã«ç¸å½)ããªããªãã æé»ã®ããã¯ã¿ã¤ãã³ã°ã«ç½®ãæãã£ã¦ãã¾ãããã®ã³ã¼ãã§ã¯ OCaml OO å¤ã®å½±é¿ãåãã¦ããã®ã§éçåä»ãã®å¿çå¦ã«æ¯ããã¦ãã¾ãããçã«éçåä»ãå¿çå¦ããèªç±ãª Rubist ãªãã° VInt 㨠Int 㯠Integer ã«ã Var 㯠String ã«ã㦠eval ã¡ã½ãã追å ãã¦ã³ã¼ãéãå°ãæ¸ããã¾ããç§ã¯â»å人ã®ææ³ã¨ãã¦ããããªãã¨ãã¡ãã絶対ãããªãã¨æããã§ããã
æ¯è¼ãã¦ã¿ã¾ããã
客観çã«ã¯æããã« FP ã®æ¹ãçããçãããåãã®ããã¨ããåã¯å¸¸ã«ããããçãã OO ã§(代æ°çãã¼ã¿åãªãã§)çãæ¸ãã®ã¯ãªããªãé£ãããã§ããâ»å人ã®ææ³ã§ã
ãã以å¤ã¯ãã Expression problem ãªã ãªæãã§åºå°½ããã¦ãã¾ãããã http://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt
è²ã
主観ã¯ããã¨æããã§ãããé¤
ã¯é¤
å±ã§ããã
ããã°ã©ãã³ã°è¨èªã®æ½è±¡æ§ææ¨ã®ãããªããããã代æ°çã«å®ç¾©ããã¦ãã対象ã¯ãã¯ã代æ°çãã¼ã¿åã§æ¸ãã®ããããããããã¯ã©ã¹ã§æ¸ãå¿ è¦ã¯ç¡ã
ã¨ããå½ããåãªâ»å人ã®ææ³ã§ãã®å確èªã¨ãªãã¾ããã
ãããªãã¨èªç¶ã¨ä»£æ°çãªå¯¾è±¡ã¯ã代æ°çãã¼ã¿åãæ¨æºè£ åã ãã®ãã¼ã«ãæã£ããè¨èªã§æ¸ãã®ãããããã¨ããâ»å人ã®ææ³ã«ãªãã¾ããããããããããã¾ãã¾â¦é¢æ°åè¨èªã§ãã£ããããããç¶æ ã«ãã£ãã¨èªèãã¦ãããã¨ããâ»å人ã®ææ³ããï¼ããªãã®å¥½ããªOOè¨èªã«ã¯ä»£æ°çãã¼ã¿åãããï¼ããããã使ãã°ããããããªãã§ãããâ»å人ã®ææ³ã§ã
ããããâ»å人ã®ææ³ã§ããã