memoizeと不動点

[id:lethevert:20050901:p4]
あ、[id:Nabetani:20050901:p2]で、C++版を書いてある。

int call( func_t * f, int x )
{
  return (*f)(x);
}

void fix( maker_t g, func_t & f )
{
  func_t x = bind( call, &f, _1 );
  f = g(x);
}

bindがみそ?

      • -

せっかくだから、Concurrent Cleanも書いときましょ

module fib

import StdEnv

Start
	# fib = fix fib_maker
	# lst = [1, 2, 3, 4, 5]
	= map fib lst

fib_maker f
	= fib_maker`
where
	fib_maker` x
		| x <= 1	= 1
		| otherwise = (f (x-1)) + (f (x-2))

fix g
	= g (\ x = fix g x)

でも、fix gの部分が不満。あのように書きたい。

      • -

よく見たら、ラムダはいらないし。

fix g
	= g (fix g)

しかも、元のBlogに書いてあるし
http://www.kmonos.net/wlog/52.php#_0049050830
まあ、いずれにしても、下の書き方に興味があるわけで、Cleanで実装できることには、実はあまり興味がなかったり。

function fix(G)
{
  function f(x) { return f(x) }
  f = G(f)
  return f
}

[id:SaitoAtsushi:20050902]に、Scheme版がありますけど、Clean版と変わらないな。やっぱり、JavaScriptだからこう書けるのか?

GUIコンポーネントとインターフェース(2)

[id:lethevert:20050902:p1]
[id:ytqwerty:20050902]

インターフェースのシリアライズ

Interfaceをそのままシリアライズすることができないことは、理解してますよ。でも、できると思えば、簡単な回避方法はあります。
下のように(今度はDelphi形式で)すれば、インターフェースを受け取るコンポーネントでも、実装クラス側をシリアライズできます。というか、僕は普通にやってることなんですが・・・

interface

type
  IHoge = interface
    function GetLabel: string;
  end;

  THogeImpl = class(TComponent, IHoge)
  public
    function GetLabel: string;
  end;

  THogeView = class(TSuperVisualComponent)
  private
    FHoge: IHoge;
  published
    property Hoge: IHoge read FHoge write FHoge;
  end;

procedure Register;

implements

procedure Register;
  begin
    RegisterComponents('Samples', [THogeImpl, THogeView]);
  end;

(2005/9/4 追記 publishedをpublicと間違えてました_| ̄|○ [id:ytqwerty:20050903]

Windowsのコントロールをデータオブジェクトとして使うべきなのか?

ここは、考え方かもしれませんが、データはデータであって描画コンポーネントではないと思います。
もし、描画コンポーネントの内部データ構造をデータの置き場にするなら、データをいろいろなところにもちまわるには、もっとも素直な方法は描画コンポーネントごと持ち歩くことで、それは普通はありえないので、データのエクスポート&インポートを各所で行う必要があるわけです。でも、それは隠蔽できるし、ライブラリなら隠蔽してほしいのです。

一般的なインターフェースは存在しないこと

[id:soutaro:20050901:1125621086]でも指摘されていたことですが、誤解があるようです。
木構造データを定義したインターフェース」ではなく、「木構造データへのアクセスを定義したインターフェース」と言ったつもりなんです。
言いたかったのは、「GUIのインターフェース」ではなく「データアクセスのインターフェース」だと。でも、もっとよく考えれば、「データの走査方法のインターフェース」という方がより正しいのではないかと。
それからですね、一般的な木構造というものがありえないなら、一般的な木構造を表示する描画コンポーネントもありえないわけで、でもそんなのおかしいでしょ。木構造ってそんなに複雑ですか?
インターフェースをインプリすれば、描画コンポーネントにはまりますということよりも、描画コンポーネントにべったりのデータの方が、複数言語間の変換がらくだというのは、さっぱり分からないです。普通に考えれば、逆じゃないですか?インターフェースであるということは、その実装には無関心だということですから、言語からの強制はよりゆるいと考える方が正しいと思います。だって、インターフェースを実装するかどうかは、開発者にまかされているし、後から実装することもできるんですから。

インターフェースのメソッドが不足していること

この点は、いくつかの論点が混ざっていると思っています。

  • データ構造を正しく走査、更新するために必要なメソッドが不足している
  • データと関係ない描画関連のプロパティ(フォントやアイコンなど)を取得するためのメソッドが不足している
  • TreeViewに対応するべきインターフェースは、NodeではなくTreeであるべきだったこと
  • インターフェースは必要な単位に分割して、複数用意してもよいこと

長いので、これは、明日にします。

おまけ - swing

実際に僕がGUIアプリケーションを作るのに使っているのは、Delphiばかりなので、swingのことはさらに知らないんです。というわけで、swingがそういう構造をしていることは、実は勉強になっていたりして。

GUIコンポーネントとインターフェース

[id:soutaro:20050901:1125614439]

GUIにデータを表示するために、オブジェクトにGUIのためのインタフェースを実装しておくことは、不自然な気がします。いや違うな。不自然とかじゃなくって、経験的にそれはやらないな、と思うわけですね。特に、DelphiとかVBとかC#とかの場合に限ると。

(あれこれ議論しながら考えがまとまってきたところもあるので、前に書いたこととちょっと違うことを言うことになるかもしれませんが、)
[id:lethevert:20050829:p5]に挙げた

interface Node
{
  Node getChild();
  Node next();
  Node getParent();
  String getLabel();
}

というのは、GUIのためのインターフェースというよりも、木構造オブジェクトに対する一般的なアクセス方法を定義したインターフェースではないかと思うのです。だから、木構造データの表示GUIコンポーネントは、木構造アクセスインターフェースを実装したオブジェクトなら、どういうオブジェクトでも表示できます、というほうが設計としてよいのではないか、ということです。木構造アクセスインターフェースを、木構造データにあらかじめ実装しておくことは、それほど不自然ではないように思いますし。

表示したいオブジェクトのクラスに特定のインタフェースを実装しておかなくてはいけないという状況は、おかしいと思うんですよ。AとBとCで表示するかもしれないから、それぞれに対応するIAとIBとICを実装しておこう、なんてばかげてると思うわけです。あるいはIAを実装しないオブジェクトを表示しようと思ったら、そこで行き詰るわけですし。

データオブジェクトがあらかじめ作られていて、かなり時間がたってから、データオブジェクトに手を加えずにGUIコンポーネントで表示する、というような局面では、まあ、そうなのかもしれません。
しかし、GUIの表示コンポーネントの方がライブラリとしてあらかじめ作られていて、個々のケースに合わせてデータオブジェクトを作っていくことになるのが、普通だと思います。そのときに、最初にデータオブジェクトを設計・実装する段階では、GUIからアクセスすることは考えずに、対処したい問題に適した形でデータオブジェクトを作成する(おそらく、DBなどにデータを永続化するような部分が意識の中心にある)はずで、データオブジェクトができてから、そのデータをどうやって表示しようということになると思います。(実際のコーディングの順序は、人によると思いますが、少なくとも設計レベルでは、データが決まってから表示を考えるのは間違いないはず)
そうなったときに、TTreeViewで表示する項目は、TTreeNodeもしくはその派生クラスでないとダメですよ、ということになっていると、解決策としては、

  1. さっきのデータオブジェクトと対応するTTreeNodeオブジェクト(またはそのサブクラスのオブジェクト)を両方作り、2重管理する
  2. さっきのデータオブジェクトを、TTreeNodeオブジェクトのサブクラスとして作り直す

ということを考えなければいけないのです。2重管理の方は、データオブジェクトを変更すると、対応するTTreeNodeオブジェクトやその仲介クラスも変更するという2重メンテが発生し、TTreeNodeオブジェクトのサブクラスとして作り直すという方は、すでにデータオブジェクトが何かのサブクラスであった場合には、多重継承でなければ解決できない問題が発生してしまいます。また、サブクラスにすることで、本来、データとは関係のないメソッドやフィールドがデータオブジェクトに追加されるという気持ちの悪いことも起こります。
さらに、こういうコードは、GUIコンポーネントとデータオブジェクトが癒着した構造になりやすいので、再設計して、表示コンポーネントを変更しようとしたときには、必然的に大手術になってしまい、作り直したほうが速いというようなことにもなります。サブクラス化することで、本来、お互い見えてはいけないようなprivate, protectedなメソッドやフィールドへアクセスできてしまうので、それらへ直接アクセスしたコードになってしまいやすいからです。
結果的に、メンテナンスのしにくいコードが生まれてしまうのです。