getLineで標準入力から入力した文字を取得、putStrLnで文字を標準出力に表示することができます。
getLineとputStrLnのタイプをghciで見てみます。
Prelude> :t getLine
getLine :: IO String
Prelude> :t putStrLn
putStrLn :: String -> IO ()
「IO String
」とは何かというと、「IOというアクションを実行したらStringの値を生成しますよ」という意味です。haskell公式:IO入門編
「String -> IO ()
」はString型を引数に入れてIO ()が返ってくるという意味です。
というわけでgetLineで標準入力から取得したStringをそのままStringで返す関数、つまりIO String -> String
というような関数があればputStrLnの引数に入れられそうですね。
....
。。
。。。。が、haskellにはIO a -> a
というような関数が基本的に用意されていません。なぜかというとIOはアクションと呼ばれ、乱数・時刻の取得・ファイル入力など、実行するたびに異なる結果を返す可能性があるため、関数とは別物として扱っているからです。なのでgetLineはそもそも関数ではなくIOアクションと呼ばれます。
じゃあどうすればgetLineで入力した文字列をputStrLnに入れられるかというと、ここでモナドが登場します。IOアクションは「モナド」であるため、モナドから値を取り出す→その値を関数に適用する、という流れとなります。
つまり、
- getLineは
IO String
のIOアクション(モナド)なので、「IO String」からStringの値だけ取り出す - 取り出した値をputStrLnの引数に入れる
という流れとなります。
IOモナドから値を取り出す一つの方法として「<-」演算子を用います。
main :: IO ()
main = do
line <- getLine
putStrLn line
IO String
であるgetLineからStringの部分だけをとってきてlineに束縛し、putStrLn関数の引数に入れています。putStrLnはStringを引数にして IOアクションを返すString -> IO String
の関数であり、標準出力に表示するIOアクションを返します。
他にも**>>=**を用いる方法もあります。
main :: IO ()
main =
getLine >>= putStrLn
変数への束縛を行わず、getLineのStringをそのままputStrLnの引数に入れることができます。