「ふつうの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
4linesで切り分けて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。$ってただ評価するだけなのな、たぶん。
あー、ねむいよねむいよ。おやすみ。