ghcを初めて使う場合のメモ
あらすじを立ててみるテスツ。
遅延評価だとかモナドとかの用語は先につかわない。
Hello World
まずはHello World。ソース:Main.hs
module Main (main) where -- hello world main = putStrLn "Hello World"
ビルド
$ ghc --make Main.hs -o hello
これで実行ファイルhelloが出来上がる。Mainモジュールのmainがエントリーポイントになる。
コード中で、--出始まる行はコメントです。はじめのmodule Main (main) whereほ内訳は、Mainがモジュール名、(main)がエクスポートする名前のリストになってる。複数あるなら(main, foo, bar)のようにする。
$と()
文字列を二つ出してみる
module Main (main) where -- このコードはコンパイルエラです main = putStrLn ["Hello", "World"]
とリストに書いてビルドするとエラーが出る
Coudn't match `Char' against `[Char]' Expected type: Char Inferred type: [Char] In the list element: "Hello" In the first argument of `putStrLn', namely `["Hello", "Wrold"]'
リストの中身が「文字」であってほしいのに「文字のリスト」があるから困ってるという感じのエラーです。
ここでshow関数を使えば多くの型を文字列にしてくれるようです
module Main (main) where main = putStrLn (show ["Hello", "World"])
これでビルドが通るし、実行すれば["Hello", "World"]と出力されます。
かっこが必要なのは、関数が左に強く結びつくからのようです。このかっこを外すとビルドエラーが出ますがそれはputStrLnにshowを引数で渡そうとするから起こるエラーのよう。
関数を適用した結果を関数に渡すようなコードが連続すると、かっこだらけになるのですが、かっこを消す方法として二項演算子の$を使っているようです。
module Main (main) where main = putStrLn $ show ["Hello", "World"]
この$自体は何のこともない関数で f $ x = f xなので、前後が1変数づつなら$なしでも同じですが、結合順位が普通の関数適用より弱いので、使う場所を工夫すれば、かっこが必要なくなります。つまり foo (bar (buzz arg))は、foo $ bar $ buzz argと書けてしまう。
とはいえ$でかっこが消せるのは最後の引数だけだけど、Haskellコードでこの$はけっこう使われているっぽい。
do
コマンドラインパラメータを表示するコードを書いてみる。
コマンドライン引数を取り出す関数は、SystemモジュールのgetArgsがそれっぽい
mainに組み込んでみます(これはビルド不可)
module Main (main) where import System -- このコードはコンパイルエラです main = putStrLn $ show getArgs
このエラーはNo instance for (Show (IO [String]))です。showは[String]には使えるので、この邪魔なIOを外す必要が出てきます。
そこはdoを使うとよいようです
module Main (main) where import System main = do args <- getArgs putStrLn $ show args
これはビルドが通ってきちんとコマンドライン引数が表示されます。
IO〜な戻り値がでる関数はdoの中で<-に変数を入れてあげて、後ろでその変数を使うことになります。
関数
リストの内容を一行づつ出すようにします。
まず繰り返す部分を関数にして再帰的に呼び出させます。
module Main (main) where import System main = do args <- getArgs putStrEachLine args putStrEachLine strs = case strs of [] -> return () head : tail -> do putStrLn head putStrEachLine tail
まず引数をcaseで条件分岐させます。空リスト[]の場合はreturn ()、何か入ってるときはputStrLnして残りを再帰的に呼び出します。
明示的にcaseを使わずはじめからパターン分岐で定義もできます
module Main (main) where import System main = do args <- getArgs putStrEachLine args putStrEachLine [] = return () putStrEachLine (head : tail) = do putStrLn head putStrEachLine tail
要かっこ
モジュール分割
このputStrEachLineを別モジュールに書いてみます
MyLibs/Print.hs
module MyLibs.Print (putStrEachLine) where putStrEachLine [] = return () putStrEachLine (head : tail) = do putStrLn head putStrEachLine tail
Main.hs
module Main (main) where import System import MyLibs.Print main = do args <- getArgs putStrEachLine args
ビルドは同様に
$ ghc --make Main.hs -o hello
Main.hsで使ってるライブラリもタイムスタンプを見てビルドしてくれます
ライブラリ単体をコンパイルする場合は、
$ ghc -c -O MyLibs/Print.hs
Preludeとか
mapMなどで置き換え...
データ型
カレンダーを作る。。。