Delphi : クロージャ
[id:lethevert:20060107:p1]で作成したクロージャを使って、memoizeとfixの問題「[id:lethevert:20050904:p3]」を書こうと思っているのだけれど・・・
maker関数が上手く作れない。というのは、IClosureとPointerを交換できないのだ。(前回、TObjectとして定義したIClosureは、Pointerを使って書き直している)
クロージャオブジェクトを複数のパターン作成するのはなるべく避けたいのだけれど・・・
-
-
- -
-
と思ったのだが、自己解決した。
recordでインターフェースを包んでしまえばよい。
-
-
- -
-
と思ったのだが、やはり上手くいかない・・・。
-
-
- -
-
でけた!!
一部、レコードの解放ができていないところがあるけど、一応動く。
program fib_fix; {$APPTYPE CONSOLE} uses SysUtils, OptClosure in 'OptClosure.pas'; //キャストのエイリアス type _i = Integer; _p = Pointer; //IClosureのラッパー type PClosure = ^TClosure; TClosure = record _: IClosure; end; function Init(c: IClosure): PClosure; begin New(Result); Result._ := c; end; procedure Final(e: PClosure); begin Dispose(e); end; //固定点を求める関数 function fix(maker: IClosure): IClosure; function f(obj: Pointer; maker: PClosure): Pointer; var ff: TClosure; //受け渡しのみ begin ff._ := _(@f, Init(maker._), @Final); Result := PClosure(maker._._(@ff))._._(obj); end; begin Result := _(@f, Init(maker), @Final); end; //フィボナッチ関数を作る関数 function fib_maker(ff: PClosure): PClosure; function f(I: Integer; ff: PClosure): Integer; begin if I = 0 then Result := 0 else if I = 1 then Result := 1 else Result := _i(ff._._(_p(I-1))) + _i(ff._._(_p(I-2))); end; begin New(Result); //TODO: この解放が行えていない。 Result._ := _(@f, Init(ff._), @Final); end; var fib: IClosure; I: Integer; begin //フィボナッチ関数の作成 fib := fix(_(@fib_maker)); //テスト実行 for I := 0 to 10 do begin Writeln(IntToStr(I) + ' -> ' + IntToStr(_i(fib._(_p(I))))); end; end.
ちなみに、ここでつかっったOptClosure.pasは、以下です。
unit OptClosure; interface type TClosureFunction = function (obj: Pointer): Pointer; TClosureProcedure = procedure (obj: Pointer); TClosureFunctionWithEnv = function (obj, env: Pointer): Pointer; TClosureFunctionM = function (obj: Pointer): Pointer of object; TClosureProcedureM = procedure (obj: Pointer) of object; IClosure = interface function _(obj: Pointer): Pointer; end; function _(aFunction: Pointer): IClosure; overload; register; function _(aFunction: TClosureFunction): IClosure; overload; register; function _(aProcedure: TClosureProcedure): IClosure; overload; register; function _(aFunction: TClosureFunctionM): IClosure; overload; register; function _(aProcedure: TClosureProcedureM): IClosure; overload; register; function _(aFunction, aEnv, aFinal: Pointer): IClosure; overload; register; implementation // ============================================================================= // 通常関数と関数内関数向け // ============================================================================= type TClosureF = class(TInterfacedObject, IClosure) private fFunction: TClosureFunction; fContext: Pointer; function _(obj: Pointer): Pointer; end; function mkClosureF(aCode: Pointer): IClosure; register; function make(aCode, aContext: Pointer): IClosure; register; var Impl: TClosureF; begin Impl := TClosureF.Create; with Impl do begin fFunction := TClosureFunction(aCode); fContext := aContext; end; Result := Impl; end; asm // begin push ebx push esi push ebp mov esi,edx mov ebx,eax // Result := make(aCode, EBP) mov ecx,esi pop edx mov eax,ebx call make // end pop esi pop ebx end; function _(aFunction: Pointer): IClosure; asm jmp mkClosureF end; function _(aFunction: TClosureFunction): IClosure; asm jmp mkClosureF end; function _(aProcedure: TClosureProcedure): IClosure; asm jmp mkClosureF end; function TClosureF._(obj: Pointer): Pointer; var aContext: Pointer; begin aContext := fContext; asm push aContext end; Result := fFunction(obj); asm pop aContext end; end; // ============================================================================= // Pointer -> Pointer 型メソッド向け // ============================================================================= type TClosureFM = class(TInterfacedObject, IClosure) private fMethod: TClosureFunctionM; function _(obj: Pointer): Pointer; end; function _(aFunction: TClosureFunctionM): IClosure; var Impl: TClosureFM; begin Impl := TClosureFM.Create; with Impl do begin fMethod := aFunction; end; Result := Impl; end; function TClosureFM._(obj: Pointer): Pointer; begin Result := fMethod(obj); end; // ============================================================================= // Pointer -> () 型メソッド向け // ============================================================================= type TClosurePM = class(TInterfacedObject, IClosure) private fMethod: TClosureProcedureM; function _(obj: Pointer): Pointer; end; function _(aProcedure: TClosureProcedureM): IClosure; var Impl: TClosurePM; begin Impl := TClosurePM.Create; with Impl do begin fMethod := aProcedure; end; Result := Impl; end; function TClosurePM._(obj: Pointer): Pointer; begin fMethod(obj); Result := nil; end; // ============================================================================= // 関数(環境付き) // ============================================================================= type TClosureFE = class(TInterfacedObject, IClosure) public destructor Destroy; override; private fFunction: TClosureFunctionWithEnv; fEnv: Pointer; fFinal: procedure(Env: Pointer); function _(obj: Pointer): Pointer; end; function _(aFunction, aEnv, aFinal: Pointer): IClosure; var Impl: TClosureFE; begin Impl := TClosureFE.Create; with Impl do begin fFunction := aFunction; fEnv := aEnv; fFinal := aFinal; end; Result := Impl; end; function TClosureFE._(obj: Pointer): Pointer; begin Result := fFunction(obj, fEnv); end; destructor TClosureFE.Destroy; begin fFinal(fEnv); Inherited; end; end.