最近、トラフィック増えてきたな。

つい、この間までは、一人でつぶやき系のBlogだったのに、最近はTBやらコメントが随分増えてきた。言葉遣いとか、気をつけたほうがいいのかな? 荒れるとヤダな。
でも、あまり気にしないで、言いたい放題Blogでいたいんだよね。
あ、TB、コメントいただいている方には、いつもいつもご愛読ありがとうございます。今後とも、よろしくお願いします。

memoizeと不動点

[id:lethevert:20050902:p2]
[id:SaitoAtsushi:20050903]

(define (fix g)
  (begin
   (define (f x) (f x))
   (set! f (g f))
   f))

やっぱり、Schemeだったら書けるんですねぇ。
でも、「(set! f (g f))」が、あー、という感じ。なんか、代入していることがばればれな感じですね。仕方ないですけど。
JavaScriptの「f = G(f)」という書き方が、宣言的な表現に見えることが気に入っているんですよね。

      • -

Cleanでがんばってみた。

fix g
    # f = fix g
    # f = g f
    = f

「f = fix g」が・・・

インターフェース

[id:lethevert:20050902:p3]
[id:soutaro:20050903]
[id:ytqwerty:20050902]

WindowsのTreeViewだからだめだという件

Windowsの仕組みからだめなのなら、Windowsのコントロールのデザインが悪いのでしょう。でも、やはり、OSの提供するコントロールは複雑でも、ライブラリは、言語にあわせてそれを隠蔽しておいてほしいですね。
しかし、ともあれ、Delphiの描画コンポーネントで、インターフェースであってほしいところが継承になっているということは間違いないわけですよ。私のスタンスとして、実現可能性の話はおいておいて、理想論から話をしているわけなので、
この話は、Delphiの関数内関数が、クロージャみたいに使いたいのに使えないから、関数内関数はいまいちだ!というのと似たような思考から始まった話なのですし。(ああ、この例は、さらに混乱を生み出すかも)
それに、当初、例に出したのは、TreeViewという木構造を描画する架空のコンポーネントであって、TTreeViewという具体的なコンポーネントの実装ことは、あまり意識していなかったのです。むしろ、最近、VCLにはない他の人の書いたオーナードローするTreeViewのコンポーネントを仕事で使うことがあって、それが、VCLのやり方を踏襲していて、VCLのダサいところまで真似していたので、標準ライブラリというもののデザインセンスというのが、その言語のユーザーに対してどの程度の影響力をもっているのかということを思って、VCLは最悪、という話になったのです。(最悪というのは、明らかに大げさですけど)

移植が楽かどうかの件

これは、今ここで突っ込んでも仕方ないかな。

必要なデータのコピーを内部に持つ件

これは、私は、一度も否定していないと思いますが。というか、コントロールに現在のデータを保持することは、内部実装として必要だとは思います。
それから、データオブジェクトと描画コンポーネントの同期ですが、かならずしも、同じタイミングで行われる必要はないんじゃないでしょうか? データオブジェクトの方の変更は、必要なときに、描画コンポーネントのメソッドを呼び出して、同期できればいいと思います。描画コンポーネントの変更は、コールバックですかね。

TreeView(架空)に対するもうちょっと現実的なインターフェースの例

ちゃんとした例を出さないと、議論が斜めに進みそうです。だから、ちょっと長いですが、書いてみます。(TTreeViewのことは、今回も意識していないです)
インターフェースを、ITreeWalkerに変更しました。それから、描画に関連するデータは、NodeViewの方に持つようにして、データとNodeViewの関係を、INodeIdentifierで取り持つようにしました。プロパティのread, writeは省略していますが、適当に補って考えてください。

interface

type
  (** まずは、インターフェース **)
  NodeView = class;
  TreeView = class;
  INodeIdentifier = interface
    function Equals(id: INodeInterface): Boolean;
  end;
  ITreeWalker = interface
    function GetRoot: ITreeWalker;

    function GetNext: ITreeWalker;
    function HasNext: Boolean;

    function GetPrev: ITreeWalker;
    function HasPrev: Boolean;

    function GetChild: ITreeWalker;
    function HasChild: Boolean;

    function GetParent: ITreeWalker;
    function HasParent: Boolean;

    function Move(id: INodeIdentifier): ITreeWalker;
    function IsValidIdentifier(id: INodeIdentifier): Boolean;

    function GetNodeView: NodeView;
  end;

  (** 続いて、ノード描画コンポーネント **)
  NodeView = class(TCustomControl)
  ...
  //ノードの描画に関するプロパティやメソッド
  ...
  public
    property Identifier: INodeIdentifier;
  end;

  (** 最後の、ツリー描画コンポーネント **)
  TreeView = class(TCustomControl)
  ...
  //ツリー描画に関するメソッド
  ...
  public
    procedure UpdateTree; //データの再走査を促す
    function GetSelected: INodeIdentifier;
    procedure Select(id: INodeIdentifier);
  published
    property Walker: ITreeWalker;
  end;
      • -

INodeIdentifierの比較メソッドがなかった。