「ふつうのHaskellプログラミング」読みます(3)
4章やる。
4.1 コマンドライン引数の処理とモジュール
echo.hs
import System main = do args <- getArgs putStrLn (unwords args)
SystemモジュールのgetArgsアクションを使ってる。これは
main = do args <- System.getArgs putStrLn (unwords args)
と、gtArgsがSystemモジュールに属してることを明示してもよい。
% ghc echo.hs -o echo % ./echo hoge fuga moge hoge fuga moge
System.getArgsアクションはコマンドライン引数を文字列のリストで渡す。それをunwordで連結してputStrLnで出力。
import System main = do args <- System.getArgs putStr (unlines args)
unlinesでくっつけると以下のような結果に。
% ghc echo.hs -o echo % ./echo hoge fuga moge hoge fuga moge
ああ、unlinesは要素の末尾に改行追加するんだった。
Haskellプログラムはモジュールという単位に分割されてる。リファレンスマニュアルどこでダウンロードできるんだろうと探したら、既に「C:\ghc\ghc-6.8.2\doc」に展開されてた。Linuxとかならきっと/usr/share/doc以下のghcほげほげとかそんなディレクトリにあるんじゃないかなきっと。Debianだとghc6-docとかいうパッケージ名で入れれた。
モジュール一覧見てると、色々できそうに思えてくる。
Mainモジュール
main変数はMainモジュールに属する。Mainモジュールは一覧に見あたらん。mainしか無かったりするのかもしれない。
Preludeモジュール
基本的な色々なのある。今まで使った関数とかアクションなんかはここに属している。
4.2 総合演習
fgrep.hs
import System main = do args <- getArgs cs <- getContents putStr (fgrep (head args) cs) fgrep pattern cs = unlines (filter match (lines cs)) where match line = any prefixp (tails line) prefixp line = pattern `isPrefixOf` line
こうか。
% ghc fgrep.hs -o fgrep fgrep.hs:8:30: Not in scope: `tails' fgrep.hs:10:27: Not in scope: `isPrefixOf'
Listをimportするの忘れてた。
import System import List main = do args <- getArgs cs <- getContents putStr (fgrep (head args) cs) fgrep pattern cs = unlines (filter match (lines cs)) where match line = any prefixp (tails line) prefixp line = pattern `isPrefixOf` line
% ./fgrep main <fgrep.hs main = do args <- getArgs
おっけーです。where節はローカルな関数とか定義するのに使うようです。filter、anyはよくあるあれ(ひどい)。isPrefixOf a bはaがbの先頭に一致するときTrue、それ以外Falseを返す関数。tailsは[渡されたリストそのもの、第2要素以降、第3要素以降、……]というリストを返す関数。
`hoge`は演算子として定義せんでも中置記法として使えるようにする構文糖のようです。いいよ中置記法とか。
Prelude> import List Prelude List> tails [1,2,3,4] [[1,2,3,4],[2,3,4],[3,4],[4],[]] Prelude List> isPrefixOf [1,2] [1,2,3,4] True Prelude List> isPrefixOf [] [1,2,3,4] True Prelude List> isPrefixOf [3] [1,2,3,4] False
4.3 まとめ
MainモジュールとかPreludeモジュールとかあるらしいですよ。
遊ぶ
Preludeモジュールのドキュメント見ててcurryとuncurryなるもの見つけたんで、想像で遊ぶ。
Prelude> let plus3 n = n + 3 Prelude> let myMap = uncurry map Prelude> myMap(plus3, [1,2,3]) [4,5,6] Prelude> let plus3xs = curry myMap plus3 Prelude> plus3xs [1,2,3] [4,5,6]
4.4 練習問題
sort.hs
main = do cs <- getContents putStr (unlines (sort (lines cs)))
だんだんLispっぽくて素敵な見た目になってきましたね。
% ghc sort.hs -o sort % ./sort cdef cccc abcd acde abcd acde cccc cdef
group.hs
こんなんだろーと考えたら
import List main = do cs <- getContents putStr (unlines (group (lines cs)))
% ghc group.hs -o group group.hs:3:34: Couldn't match expected type `Char' against inferred type `String' Expected type: [Char] Inferred type: [String] In the first argument of `group', namely `(lines cs)' In the first argument of `unlines', namely `(group (lines cs))'
全然違った。groupってこんなん。
Prelude List> group [1,1,2,3,3] [[1,1],[2],[3,3]]
じゃあこうですね。
main = do cs <- getContents putStr (unlines (map head (group (lines cs))))
いよいよますますLispじみてきて楽しいですね。おもわずputStrも括弧でかこむところでした。
% ghc group.hs -o group % cat >test hogehoge hogehoge fuga moge moge % ./group <test hogehoge fuga moge
おっけーです。