抱著「關於函數語言有一些話想說,想釐清一些誤會」的想法報名了OSDC。原本就覺得這是個不容易講好的主題,準備時又發現比想像困難許多。
事後看到IRC Log的一些留言,投影片誤植Java支援lambda的版本為Java7,實為Java8,謝謝wcpan的指教,投影片已更正。
另外,有人問「rand()算不算pure function呢?」這是一個有趣的問題。若討論C stdlib的rand(),其實這個函數使用了廣域的亂數種子,可由srand()函數設定。每次呼叫rand()時,便會更新廣域狀態,並回傳一個亂數。所以,C的rand()違反了pure function的兩個定義:不讀取或寫入廣域狀態,給予同樣的參數(沒有參數)得到不同結果。
那有沒有可能將亂數定義為純函數呢?
- 密碼學的block cipher在加密和解密時使用擬亂數產生器,產生相同的亂數序列作為每個block加密的密鑰。在討論密碼學時,常會定義pesudo random function為prf(key, seq) :: 位元串列->位元串列->位元串列 (參考Standford密碼學課程對PRF的說明)。參數key為密鑰(也可想成seed),seq為計數器,要產生不同亂數時以seq=0, 1, 2…代入。這是一個數學上的純函數,給予相同定義的參數,一定會得到同樣的結果,
- 在Haskell的System.Random module中,則同時提供了pure及impure的兩種實作:
- next :: g -> (Int, g) : next 是一個函數,傳入一個亂數產生器後,會得到一個整數亂數,和一個新的亂數產生器。這也是一個純函數的定義。
- 文件中的getStdRandom型別有些複雜,但可以文件的範例rollDice :: IO Int。RollDice是一個IO Monad,可能會造成副作用(修改廣域狀態)並回傳一個整數值。
「產生相同亂數序列」在程式上有許多的運用,如block cipher加密、測試隨機演算法時可以deterministic的重製演算結果、連線遊戲的同步…等。
最後附上投影片。