ダイナミックな型システム

[id:m-hiyama:20050903:1125731280]
僕もあまり詳しくないですが、RubyのDuck Typingなんかは、こういうのを上手く扱えそうな気がします。動的にメソッドを追加する場合も、大丈夫かな?
でも、Duck Typingって、同音異義語/句に対して弱そうだが、どうなんだろう?

memoizeと不動点

[id:lethevert:20050903:p2]
できた!!

fix g = f
where
    f = g f

whereを使えば書けたんだ。
ということで、memoizeも含めたConcurrent Clean版は↓です。(リストの選択に必要な計算量はこの際無視で)

module memo

import StdEnv

Start
    = map fib [1,2,3,4,5]

//fib = fix fib_maker
fib = fix_memo fib_maker
where
    fib_maker :: (Int -> Int) Int -> Int
    fib_maker f 0 = 0
    fib_maker f 1 = 1
    fib_maker f n = f (n-1) + f (n-2)

fix :: ( (Int -> Int) -> (Int -> Int) ) -> (Int -> Int)
fix maker = f
where
    f = maker f

fix_memo :: ( (Int -> Int) -> (Int -> Int) ) -> (Int -> Int)
fix_memo maker = f
where
    f = (!!) tbl
    tbl = map (maker f) [0..]

参考)
http://d.hatena.ne.jp/tanakh/20041126#p2
http://sky.zero.ad.jp/~zaa54437/programming/clean/CleanBook/part1/Chap6.html#sc6
http://www.kmonos.net/wlog/52.php#_0308050827

      • -

括弧のネストが、注釈になってしまった。HatenaでLispSchemeのソースをコピペのは、かなりめんどくさい予感

      • -

上のソースを使って、いろいろ遊んでいたら、変な数字が出てきた。よく考えたら、CleanのIntは32ビット整数値なのだった。HaskellのIntegerのような任意精度の整数ってないのかな?

委譲

[id:soutaro:20050903:1125679890]
委譲って、こういうやつですよね。

class Printer {
    Writer writer;
    void write(String s) {
        writer.write(s);
    }
    ...
}

class Writer {
    void write(String s) {
        ...
    }
}

これは、私もやらないですね。下のように書けばいいと思いますから。

printer.writer.write("hello!");

でも、逆に、これでいいと思うので、下のようなコードは、書きたくないかも。なぜって、こういう風に書かれたコードは、すぐに見通しが悪くなって、メンテナンスしにくくなるからなんです。自分だけで開発が閉じていれば、たいした問題に感じないですけど、他人が書いたコードを読んでいると、かなり読みにくく感じます。特に、ドキュメントがない(少ない)と、ソースに対してgrepをかけまくることになりがちです。

class Printer extends Writer {
    ....
}

もし、PrinterとWriterを同じ型のオブジェクトとして使いたいなら、初めて上のパターンが選択肢として浮上しますけど、これよりも、インターフェースを使った下の形式の方がずっとよいと思います。そして、ここで初めて、委譲を使う可能性が出てくるのだと思います。

interface WriterIntf {
    void write(String s);
}

class Writer implements WriterIntf {
    void write(String s) {
        ....
    }
}

class Printer implements WriterIntf {
    void write(String s) {
        ....
    }
}
      • -

他に、委譲を使う可能性といえば、メソッド名を変えたいときや、一部の実装だけを利用したときや、ユーティリティオブジェクトを利用する場合なんかがあるのかな。でも、そういうのは、たいてい丸投げではないので、いわゆる「委譲」というのとはちょっと違うのかも。ただ、そういう目的のために、「継承」を使っているコードは見るので、対立概念として「委譲」といってもいいかも。

実装の共有

継承というのは、純粋に実装の共有をするという目的には、必ずしも適っていないところに問題があるのだと思います。つまり、継承は、振る舞いとその実装の両方を共有する機構であって、その2つを区別できないという問題を持っているのです。
振る舞いのみを共有したいなら、インターフェースを用いることができるのですが、
実装のみを共有したいなら、継承以外の別の方法を考える必要があって、それの一番有力な候補が委譲なのでしょう。