遅延評価についてもう少し
次の例を考えてみます。
Prelude> let foo = 1 : map (+1) foo Prelude> take 10 foo [1,2,3,4,5,6,7,8,9,10]
例えば、機械的に四つ目の要素を計算する部分を書いたら次のようになりますよね。
Prelude> 1 : map (+1) [1,2,3] [1,2,3,4]
五つ目はこう。
Prelude> 1 : map (+1) [1,2,3,4] [1,2,3,4,5]
という事は、この関数は次の要素を計算する度に、何度もリスト全体にmap関数を適用しているという事になります。
もしかして、これってすごく効率が悪いんじゃないでしょうか?
同じようにリストを生成する処理なら([1,2..]とすれば良いのは一旦おいといて)次のように書く方法もあります。
Prelude> let fooc a b = a : fooc b (b+1) Prelude> let foo = fooc 1 2
こちらのほうが効率が良いように感じるのですが、実際にはどうなんでしょう?
昨日のフィボナッチ数の計算も。
Prelude> let fib1 = 0 : 1 : zipWith (+) fib1 (tail fib1)
かっこよくこう書くより。
Prelude> let fibc a b = a : fibc b (a+b) Prelude> let fib2 = fibc 0 1
律儀にこうやって書いたほうが処理は高速という事になるのでしょうか。
Haskellには、criterionというベンチマークフレームワークがあるようなので、近いうちにこれを導入して測定してみようかと思います。
蛇足:
このブログを読み直してると感じる事なのですが、自分の場合「車輪の再発明」が多いような気もします。もっと効率の良い学習方法もあるとは思うのですが・・・。