「ふつうのHaskellプログラミング」読みます(1)
Haskel Hackathlonに申し込んだ手前Haskell知らなくちゃ話になんねえので、通称ふつハス本買ってきました。とりいそぎ2章あたりまで読んだので手元で試した記録のっける。
私の知識はHaskell知識はhttp://www.kmonos.net/wlog/65.html#_1549060908読んだことあるくらいです。
はろわはろわ
% ledit >hello.hs main = putStrLn "Hello, World!" % runghc hello.hs Hello, World!
モナドとか怖いとかはろわですらむずかしいって言ったの誰だ! (少なくとも一見)簡単じゃないか!
leditは便利なcatコマンドみたいなものです。
じゃあ以下2章で例示されてるプログラムを順にやってく。
cat
% ledit >cat.hs main = do cs <- getContents putStr cs % runghc cat.hs <cat.hs main = do cs <- getContents putStr cs % ghc cat.hs -o cat % ./cat abc abc def def
なんかcatできてますね! なんですかC言語とかJavaなんかよりずっと楽じゃないですか。これが一括読み込み書き込みじゃなくて逐次処理になる理由はよくわかんないけど。
getContentというアクションをcsに束縛して、putStrにcsアクションを渡すとかなんとか。getContentのアクションは評価が遅延されて、putStrに渡されたときに入力とってくるアクションが評価されてそれをputStrするアクションが評価される、とか想像してみた。よくわかんないですね。
ところで、このcat.hsをrunghcするとわけわからんこってなりました。
% runghc cat.hs aabbcc ^D cat.hs: exception :: GhcException
なんでしょうね。^D打っても終了できなかったんで^Cで終了しました。よくわかんないですね。先に進みましょう!
countline
つぎはcountlineコマンド。wc -l
相当ですね。
% ledit >countline.hs main = do cs <- getContents print $ length $ lines cs % ghc countline.hs -o countline % ./countline aaaaaaa bbbbbb ccc d 4
linesで切り分けてlengthで数えてprintで書く。むずかしいことは無いですね。getContentとかの真意とかを考えないでいれば。あと個人的に
% ledit >countline.hs main = do cs <- getContents (print (length (lines cs)))
こう書くとちょっと安心するかも! linesとlengthは名前通りのこんなんだよねー。
Prelude> lines "1\n22\n333\n444" ["1","22","333","444"] Prelude> length $ lines "1\n22\n333\n444" 4
head
tailコマンド知ってたけどheadコマンド知らんかった。
% cat head.hs main = do cs <- getContents putStr $ firstNLines 10 cs firstNLines n cs = unlines $ take n $ lines cs % ghc head.hs -o head % ./head </usr/include/stdio.h /* Define ISO C stdio on top of C++ iostreams. ...
できたできた。これはこういうことですね
Prelude> lines "1\n22\n333\n4444" ["1","22","333","4444"] Prelude> take 2 $ lines "1\n22\n333\n4444" ["1","22"] Prelude> unlines $ take 2 $ lines "1\n22\n333\n4444" "1\n22\n"
tail
headの逆。
% cat tail.hs main = do cs <- getContents putStr lastNLines 10 cs lastNLines n cs = unlines $ takeLast n $ lines cs takeLast n ss = reverse $ take n $ reverse ss % ghc tail.hs -o tail tail.hs:2:17: Couldn't match expected type `String' against inferred type `Int -> String -> String' In the first argument of `putStr', namely `lastNLines' In the expression: putStr lastNLines 10 cs In the expression: do cs <- getContents putStr lastNLines 10 cs
おおっと噂のおそろしいエラーが出てきましたね。tail.hsの2行目の17文字目が怪しいらしいってさ。
「期待してる型はStringなのにInt -> String -> Stringとかいう型の値が来てるよー」とかかな。putStrにlastNLinesを渡してるからこんなこと言われたんですね。putStrの後ろに$を付けるの忘れてました。
% cat tail.hs main = do cs <- getContents putStr $ lastNLines 10 cs lastNLines n cs = unlines $ takeLast n $ lines cs takeLast n ss = reverse $ take n $ reverse ss % ghc tail.hs -o tail % ./tail </usr/include/stdio.h ... #endif /* !_STDIO_H */
できましたね。よかったよかった。新たに使ってんのはreverseくらいですかね。
Prelude> reverse [1,2,3,4,5] [5,4,3,2,1] Prelude> take 2 $ reverse [1,2,3,4,5] [5,4]
ほうほう。
まとめ
putStr, putStrLn, printが返すのは「アクション」らしいですよ。getContentsとやらは「アクション」そのものらしい。なんでしょうね、アクション。夢が広がりますね。他の関数に関してはごく普通に色々してくれるリスト操作の関数でしたね。
練習問題
countbyte
こんなんかなー
% cat countbyte.hs main = do cs <- getContents print length cs % ghc countbyte.hs -o countbyte countbyte.hs:2:10: Couldn't match expected type `String -> IO t' against inferred type `IO ()' In the expression: print length cs In the expression: do cs <- getContents print length cs In the definition of `main': main = do cs <- getContents print length cs
またやっちまった。これだとprintにlengthとcsを渡してることになっちゃう。こうですね。
% cat countbyte.hs main = do cs <- getContents print $ length cs % ghc countbyte.hs -o countbyte % ./countbyte <countbyte 399922 % ls -l countbyte -rwxr-xr-x 1 sun sun 399922 2008-01-27 04:00 countbyte*
あってるあってる。
countwords
% cat countword.hs main = do cs <- getContents print $ length $ words cs % ghc countword.hs -o countword % ./countword <countword.hs 12
えーと、あってますね。よかったよかった。
あそび
文字列は文字のリストらしいですよ。あと中置記法の演算子は、例えば+なら(+)がそのものらしいですよ。構文糖ですねさては。
Prelude> [] [] Prelude> 2 : 1 : [] [2,1] Prelude> ((:) 2 ((:) 1 [])) [2,1] Prelude> 1 + 2 + 3 6 Prelude> ((+) 1 ((+) 2 3)) 6 Prelude> take 2 $ reverse [1,2,3,4,5] [5,4] Prelude> (($) take 2 (reverse [1,2,3,4,5])) [5,4]
これなんてLisp。$ってただ評価するだけなのな、たぶん。
あー、ねむいよねむいよ。おやすみ。