余談ですよ2

http://www.jmuk.org/d/?path=2006/01/08#d08t02
[id:soutaro:20060108]
sequenceがあっても、mapがなければループを自前で書く必要があるわけで、じゃあ、ループをfor文なしにどう書くの?といったら、再帰構文で書けるから要らないよ、ってことでしょ、という話だと考えていたのだけれど・・・
そもそも、末尾再帰の最適化をしない言語の場合は、再帰構文でループを書くことができない。だから、そういう言語(CやJavaPascalや・・・)では、while文やfor文は、言語にとって不可欠の存在だということ。それに対し、末尾再帰の最適化をする言語(LispやMLやHaskellや・・・)では、while文やfor文は、単なる構文糖衣に過ぎない。

      • -

でも、なぜ(while文ではなくて)「for文」がないのか?ということなら、sequenceがあるからとかmapがあるからとかという理由であたっていると思う。for文というのは、シーケンスや配列操作を楽にするための、while文に対する構文糖衣だとも言えるからだ。

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は、以下です。

続きを読む