Haskellにおける標準入力と標準出力

ほとんどのプログラミングでは副作用は必要不可欠です。 Haskellの世界では純粋なコードの副作用から完全に分離されます。

Haskellの関数に副作用がある場合、IOのマークが付与されます。

標準入力と標準出力

Haskellにおける標準入力はgetLine関数を使用します。

逆に、putStrLn関数は標準出力を行います。

main = do
    putStrLn "Greetings!  What is your name?"
    inpStr <- getLine
    putStrLn $ "Welcome to Haskell, " ++ inpStr ++ "!"

入力結果

> runghc basicio.hs
Greetings!  What is your name?
John (入力)
Welcome to Haskell, John!

標準入力と標準出力の型

putStrLnの型にもgetLineの型もIOの文字が入っていると思います。 これは、関数に副作用が含まれていることの印です。

ghci> :type putStrLn
putStrLn :: String -> IO ()
ghci> :type getLine
getLine :: IO String

IOアクションはむやみやたらに呼べない

I/Oアクションをもった関数はいくらでも作ることができます。ただし、I/Oアクション内からのみ呼び出すことができます。

例えば、main関数自体もI/Oアクションのtypeを持っています。

main :: IO ()
main = do
    putStrLn "HelloWorld"

純粋 vs 不純

  • 純粋な関数
    • 同じパラメータを指定すると、常に同じ結果が生成されます
    • 決して副作用がありません
    • 状態を変更しません
  • 不純な関数(I/O)
    • 同じパラメータに対して異なる結果を返すことがあります
    • 副作用がある可能性があります
    • プログラム、システム、世界のグローバルな変数を変更する可能性があります。

なぜ純粋が大事なのか

Haskellでは意地でも純粋なコードとI/Oアクションを明確に区別しようとします しかし、ほとんどの言語ではこの区別がありません。CやJavaPythonではどこからでも標準入力関数を呼び出すことができます。 同じ引数で同じ結果を返すのかどうか、グローバルな世界で何かを変更する可能性があるのかどうかを確認するためには、ドキュメントを読む以外ありません。

副作用をI/Oアクションへ分類するHaskellのやり方は、コードに明確な教会を生み出します。 副作用のないコードにより、プログラムの純粋な部分で予期しない結果が生じていないことを常に確認できます。

これにより、常に予想外の動作を行う可能性のある副作用のあるコードに、デバッグで集中することができます。

<-オペレーターについて

<- オペレーターはIO()から値を取り出すために必要です。

getLine関数のサンプルを確認してみましょう。

inpStr <- getLine