だいたい私は本でも新聞でも後ろから読むという習慣があって、大切な事は最後の方に書いてあるのでそっちのほうが効率的なのです(小説と漫画はさすがに前から読みます)。そんなわけで The Haskell School of Expression 15章の途中で memo1 の事が分からなくなったので、14章にバックします。どうやら、この章には Haskell でのストリームの扱いについて書いてあるようです。
ストリームの実装は他の言語では位置情報付きバッファですが、Haskell ではリストをそのままストリームとして使います。Squeak のように位置とメモリが手に取るように分かる環境に慣れていると、単なるリストをストリームと呼ばれても意味不明ですが、ファースト・イン・ファーストさえ実現出来れば、別にただのリストでも充分なわけです。Haskell は遅延評価なのでさらにこの仕組みと相性が良いです。
ストリームプログラミングの王道はやはり echo だと思うので、SOE ほったらかしでふつケルにあった echo を例に挙げます。 > main1 = do cs <- getContents > putStr cs あまりにも味気ないし、どこにもストリーム使ってない。。。しかし、無理や り使います。多分、引数がリストで答えもリストな関数を作れば良いのです。 リストをコピーする関数を間にカマシます。 > echo :: [Char] -> [Char] > echo [] = [] > echo (x:xs) = x:(echo xs) > > main2 = do cs <-getContents > putStr (echo cs) これだと本当に意味があるかどうか分からないので、もうちょっと工夫して、 文字を二回ずつ出してみます。 > echo2 [] = [] > echo2 (x:xs) = x:x:(echo2 xs) > > main3 = do cs <-getContents > putStr (echo2 cs) 最初のうちは、"hello" と入力して "hheelllloo" と出るのがとても不思議で した。なぜ "hellohello" じゃ無いのか???? という疑問には答えずにさらに 面白い例に挑戦。いっこく堂の腹話術のように遅れて答える echo です。一文 字ずつじゃ味気ないので改行ごとに区切って返します。 > ignore x = "" -- 何を聞かれても何も答えない関数 > delay :: [String] -> [String] > delay [] = [] > delay (x:xs) = ((ignore $! head xs) ++ "\"" ++ x ++ "\""):(delay xs) > main4 = do cs <- getContents > putStr $ unlines $ delay $ lines cs init で改行を削除しています。本にはありませんが、$! を使うと、引数を無 理やり先に評価出来るという例です。多分もっとスマートに書く方法があるか と思います。実行例はこんな感じ。 Main> main4 ちわー! あれ、居ないの? "ちわー!" お、いたいた。 "あれ、居ないの?" さっきから居るよ! "お、いたいた。" どこ見てんねん。 "さっきから居るよ!" 怒るなよ! "どこ見てんねん。"
memo1 のうまい例が思いつかないので、つづく!