IOモナドとdo記法
まずはじめに、HaskellでのHelloWorld。
module Main where main :: IO () main = print "Hello,World!"
この"()"というのが気になったのですが、どうやらちゃんとPrelude(?)で定義されているようです。
Prelude> :i () data () = () -- Defined in GHC.Unit instance Bounded () -- Defined in GHC.Enum instance Enum () -- Defined in GHC.Enum instance Eq () -- Defined in Data.Tuple instance Ord () -- Defined in Data.Tuple instance Read () -- Defined in GHC.Read instance Show () -- Defined in GHC.Show
また、
Prelude> :i putStrLn putStrLn :: String -> IO () -- Defined in System.IO Prelude> :i print print :: (Show a) => a -> IO () -- Defined in System.IO Prelude>
こんな感じで、出力を表すデータ型は基本的に「IO ()」を返すようになっている事から、これらの関数をmain関数内で「手続き的に」使うための「約束事」だと思えば良いみたいです。
手続き的と言えば、例えばJavaの次のようなサンプルをHaskellで実装する事を考えてみます。
import java.util.Scanner; public class Sample { /** * aとbを取得し"a is b"を返す * @param a * @param b * @return */ private static String foo(String a,String b){ return a+" is "+b; } /** * 主処理 * @param args */ public static void main(String[] args){ Scanner scan = new Scanner(System.in); System.out.println("Please input a and b"); String a = scan.next(); String b = scan.next(); System.out.println(foo(a,b)); } }
これを関数型言語のアプローチで実装しようとすると厄介なのですが、IOモナドとlambdaを使えば次のようにして書けます。
Prelude> let foo a b = a ++ " is " ++ b Prelude> putStrLn "Please input a and b" >> getLine >>= (\a -> getLine >>= (\b -> putStrLn (foo a b))) Please input a and b Haskell Cool Haskell is Cool
可読性は良くないですが、処理が左から右に流れていく感じが、手続き処理的に見えないことも無いですね。
そこで、do記法の出番となります。
Prelude> let foo a b = a ++ " is " ++ b Prelude> do { putStrLn "Please input a and b" ; a <- getLine ; b <- getLine ; putStrLn (foo a b) } Please input a and b Haskell Cool Haskell is Cool
これは先ほどのモナドを使った例の糖衣構文だそうですが、ほとんど手続き言語に見え、それでいて(IOはモナドなので)純粋さは保たれています。Haskell勉強し始めた頃、この記法を見て違和感を感じて、ずっと遠ざけていたのですが、これでスッキリしました。
そして、do記法はインデントを使って複数行にまたがって書ける事、putStrLnの戻り値が「IO ()」な事から、次のようにmain関数を書くことができる、というワケですね。
module Main where foo :: String -> String -> String foo a b = a ++ " is " ++ b main :: IO () main = do putStrLn "Please input a and b" a <- getLine b <- getLine putStrLn (foo a b)
んー、美しい!