參考資料:
r/haskell: what is exactly side effect?
Haskell Wiki: Intro to Haskell IO/Actions

在Haskell中,一個interactive program被視為一個「以目前世界狀態為input、以改變後的世界狀態為output」的純函數(pure function),新的世界狀態反映了在程式執行過程中所產生的副作用(side effect)。

問題:副作用是什麼?如何定義?

假設有個type World用來反映世界的狀態,那麼一個interactive program便可用類別為 World -> World 的函數來表達,並簡稱為IO

1
type IO = World -> World

以使用者在鍵盤上敲敲打打的事件為例,可以把使用者敲打鍵盤之前的世界狀態視為原本的世界狀態,把使用者敲打鍵盤之後的世界狀態視為後來的世界狀態。也就是說,「敲打鍵盤」這個副作用改變了世界的狀態。

但一個interactive program除了副作用之外,我們也有可能希望能回傳值,以供後續使用。像是「使用者在鍵盤上輸入文字」這個副作用,在敲鍵盤之外,我們還希望可以從他的敲鍵盤的行為讀取(萃取?)到他所輸入的值,這個值之後可以用來繼續丟到下一個用來登入系統的函數。因此有必要重新修改一下上面對type IO的定義:

1
type IO a = World -> (a, World)

例如:

  • 「從user的鍵盤輸入而讀取來的一個字元」具有IO Char的類型。這個字元的類型之所以不只是Char,是因為要強調它是一個透過副作用(aka IO action)才得來的字元
  • 打印一個字串在螢幕上具有IO ()的類型,因為將一個字串打印在螢幕上,只是純粹改變螢幕的狀態,所以回傳一個()代表回傳空值。()稱為unit。

一個具有IO類型的表達式(expression)叫做一個IO action。

IO action的幾個範例:

  • 將字串”hello”印在console上: 具有IO ()類型
  • 從console中讀取一行input: 具有IO String類型
  • 建立一個網路連線連到 www.google.com 的 port 80: 具有IO Socket類型
  • 從terminal中讀取兩行輸入,並將兩行的輸入讀取成兩個數字,將兩個數字相加後,印在螢幕上: 具有IO Int類型
  • 一個以滑鼠動作為輸入、並將一格格的圖像顯示在螢幕上的第一人稱射擊遊戲: 具有IO ()類型

必須記住的是,一個IO action,由於本身就是一個expression,在Haskell中和IntChar一樣被當成一個值(value)來看待,既可以綁定到變數名稱上(使用letwhere)、也可以作為函數的參數、更可以作為函數的回傳值

最後這一點(將IO action作為函數的回傳值)使我們可以細緻區分putStrLn函數與該函數的回傳值之間的區別。

1
putStrLn :: String -> IO ()

putStrLn
是一個以String為參數並回傳函數,

do區塊

return