「ふつうのHaskellプログラミング」読みます(6)
7章、基本的な構文。
7.1 コメント
ラインコメントとブロックコメントあり。ブロックコメントはネスト可。
Prelude> 3 + 2 -- fuga? 5 Prelude> 3 + {- aodfjaij -} 2 5 Prelude> 3 + {- aodfja {- 11111 -} -} 8 11
あとリテレイト形式といって、基本コメントのドキュメントの中にコードを埋め込む式の方法もあるらしい。D言語のhtmlの中に書くことできる機能とかもここから来てんのかね。
7.2 レイアウト
今まではオフサイドルールと言って、式の桁を揃えることでブロックを表現する方法を使っていた。
% ghc cat.hs -o cat % ./cat <cat.hs main = do cs <- getContents putStr cs
それ以外にも、中括弧{}とセミコロン;でブロックを表現することもできます。
% ghc catb.hs -o catb %./catb <catb.hs main = do { cs <- getContents; putStr cs; }
式区切りの基本が括弧であるように、ブロック区切りの基本は中括弧て感じ。で、すーぱーべんり記法としてのオフサイドルールがある。同じ高さの部分がブロックになるわけだから、こういうこともできる。
% ghc cat.hs -o cat % ./cat <cat.hs main = do cs <- getContents putStr cs
読み易くはないと思うけど、こんなに分けることもできる。
% ghc cat.hs -o cat % ./cat <cat.hs main = do cs <- getContents putStr cs
7.3 if文
if「文」ってのがわりと大事。制御構造じゃないのです。どういうことかっていうと、if文が値を持つということ。多くのLispとかやRubyなんかと一緒ですね。
Prelude> if 3 == 2+1 then 100 else 200 100
7.4 パターンマッチ
パターンマッチです。超重要。JavaとかC++のオーバーロードとかはパターンマッチをちょっと制限して取り入れたものですよねきっと。一応Scalaで微妙に使ったことある。他の言語もなんで無いのかなと不思議に思える良い機能だと思う。良いと思うが手に馴染んでないのでもっと馴染ませる。
The Little MLerとか読んでHaskellでやるとかいいかもな。ちょっと9章のdataあたりを先取りしてLittle MLerぽい遊びをしてみよう。なんかまあ昔の自分の記録参考にしつつ。http://d.hatena.ne.jp/hogelog/20071023/p1
data ShishKebab = Skewer | Onion (ShishKebab) | Lamb (ShishKebab) | Tomato (ShishKebab) str :: ShishKebab -> String str (Skewer) = "Skewer" str (Onion kebab) = "Onion(" ++ str kebab ++ ")" str (Lamb kebab) = "Lamb(" ++ str kebab ++ ")" str (Tomato kebab) = "Tomato(" ++ str kebab ++ ")" only_onions :: ShishKebab -> Bool only_onions (Skewer) = True only_onions (Onion kebab) = only_onions kebab only_onions (Lamb kebab) = False only_onions (Tomato kebab) = False main = do putStrLn $ str (Tomato (Lamb (Onion (Lamb (Skewer))))) print $ only_onions (Onion (Lamb (Skewer))) print $ only_onions (Onion (Onion (Skewer)))
で、実行
% runhugs kebab.hs Tomato(Lamb(Onion(Lamb(Skewer)))) False True
うーんいい感じですね。ケバブケバブ。
あとまあ普通に本に乗ってる感じのを試すと、こんなんとか。
Prelude> let p (x,y) = x + y Prelude> map p $ zip [1,2,3] [4,5,6] [5,7,9]
ガードとか。
hoge x y | x == y = "eq" | x > y = "gt" | x < y = "lt" main = do putStrLn $ hoge 2 8 putStrLn $ hoge 2 2 putStrLn $ hoge 8 2
% runghc test_guard.hs lt eq gt
でもまあこの辺は使ううちに慣れてくるだろうからまあいいや。
7.5 case式
パターンマッチを関数定義以外のところで使う方法。先のパターンマッチがOCamlで言うfunctionなら、こっちはmatchみたいなものですね。
Prelude> import Char Prelude Char> case "hoge" of {"" -> ""; (c:cs) -> toUpper c : cs} "Hoge" Prelude Char> case "" of {"" -> ""; (c:cs) -> toUpper c : cs} ""
7.6 関数定義
関数の識別子として使えるのは[a-zA-Z_][a-zA-Z_0-9']*。二項演算子は
Prelude> let (///) x y = x / y / y Prelude> 27 /// 3 3.0
のように、括弧でくくることで定義できる。優先順位云々はめんどいのでパス。
7.7 定義と束縛
let式
たびたび使ってましたが。一時的に束縛できる。schemeだとかMLだとかと似たようなもんと認識。
f n = let x = n + 1 y = x + 1 z = y + 1 in x * y * z main = print $ f 2
うーん、オフサイドルールがわりとめんどいなあ
% runghc test_let.hs 60
次where節による束縛
foo i | i > 0 = square (i + 1) | i == 0 = square 0 | i < 0 = square (i - 1) where square n = n * n main = do print $ foo 1 print $ foo 0 print $ foo $ - 1
% runghc test_where.hs 4 0 4
束縛においてもパターンを用いることが可能。
Prelude> let (c:cs) = "hogehoge" Prelude> c 'h' Prelude> cs "ogehoge"
7.9 練習問題
こんなんかなあ。きたねえ気してならん。
main = do cs <- getContents putStr $ fold cs fold :: String -> String fold cs = foldIn $ splitAt 60 cs foldIn :: (String,String) -> String foldIn (line,[]) = line ++ "\n" foldIn (line,remain) = line ++ "\n" ++ fold remain
% ghc fold.hs -o fold % cat hoge aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc % ./fold <hoge aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccc cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc cccccccccccccccccccc
いちおうそれっぽい。あとはねむいからねる。
くそ間違ってた。
ねむいからといってそんな、あきらかに間違ってるのどうよ。
main = do cs <- getContents putStr $ concatMap fold $ lines cs fold :: String -> String fold cs = foldIn $ splitAt 60 cs foldIn :: (String,String) -> String foldIn (line,[]) = line ++ "\n" foldIn (line,remain) = line ++ "\n" ++ fold remain
% ghc fold.hs -o fold % cat hoge aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc % ./fold <hoge aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc cccccccccccccccccccccccccccccccc
これでよろし。