単純な入出力の実験をする。名前を入力すると挨拶する(この文書は .lhs と して保存すると実行出来る)。 > import Random -- この行は後で使う。 > sayHello :: IO () > sayHello = do putStr "What is your name? :" > name <- getLine > putStr ("Hello " ++ name ++ "!") 一見なんとも無い書き方に見えるだけに、Haskell での入出力は手ごわい。入 出力を含むコードは含まないコードと意味合いが全然違ってくる。実は Haskell では関数を実行中に入出力を行う事が出来ない。その代わり、入出力 を行うためのプログラムを返す関数を作る。例えば、"hello" は文字列を返す 式だが、putStr "hello" は文字列を表示したいという気持ちを表す式だ。こ のような式を IO 型という。putStr の型は String -> IO () 型で、受け取っ た文字列を表示したいという気持ちだけを表す。Haskell インタプリタである hugs は、評価結果として IO () 型を受け取ると、気持ちだけを受け取るわけ には行かなくてさらに実行する事になっている。 他の行を見てみる。getLine の型は IO String 型で、これは文字列を入力し たいなあという気持ちを表す。<- は代入のように見えるが、右側の入力を左 に代入したいんだけどという気持ち表す。 なぜこんなに回りくどい事をやってるかと言うと Haskell では、引数が同じ なら結果は同じ(参照透過性)だと言う約束がある。普通のプログラミング言語 では、引数が同じでもユーザからの入力なんかによって振る舞いが変わるのだ が、関数型言語ではこの変化を嫌う。しかし、プログラムには入出力が付き物 なので、Haskell は入出力を「入出力をする気持ち」に纏めて計算をする。こ れにより、気持ちの部分とそうでない部分が明確に分離する。 - 普通の言語 : プログラムを書く -> 評価実行する - Haskell : プログラムを書く -> 評価(簡約)する -> 実行する Squeak でも、プログラム自体をプログラムで書くというのは良くある技なの で、同じような事は出来るかも知れない。 次にもうちょっとましな例を示す。乱数を使った足し算テスト。ここでは Random モジュールを使っている。rollDice はライブラリにあった例をそのま ま使っているが、これは IO Int 型、つまり整数を渡したいという気持ちを表 す。他に注意がいるのは read 関数かな。これは、文字列をオブジェクトに変 換するのだが、文脈から数字にしたいのだろうと推測して数字に変換してくれ る。このあたりは Haskell の型システムの強力な部分だ。 > rollDice :: IO Int > rollDice = getStdRandom (randomR (1,9)) > exam :: IO () > exam = do q1 <- rollDice > q2 <- rollDice > putStr ((show q1) ++ " + " ++ (show q2) ++ " = ? ") > ans <- getLine > if read ans == q1 + q2 > then putStr "Correct" > else putStr "Wrong"