很神奇,在List monad中do notation的篩選功能guard不是語言內核,而是一個用Haskell寫的函數而已。
Haskell report 2010對於guard有如下敘述:
guard :: MonadPlus m => Bool -> m ()
guard b is return () if b is True, and mzero if b is False
意思是任何MonadPlus都有guard。MonadPlus都必須有mzero這一元素,在List當中就是[]。return () 在List當中的意思就是傳回[()],而。List的 xs >>= f (f是一個 a -> [a]的函數)運算是傳回 [y | x <- xs, y <- f x]。這只是一個概念上的說明,內部不是這樣實做,但是效果一樣。以這段程式為例說明guard的運作方式:
import Control.Monad
listGuard :: [Int] -> [(Int, ())]
listGuard xs = do x <- xs
y <- guard(even x)
return (x,y)
如果接著輸入 listGuard [1..4],得到的結果是[(2,()),(4,())]。
把 do nation 還原成 >>=:
xs >>= \x -> guard(even x) >>= \y -> return (x, y)
在收集y的過程中,注意到 y <- f x ,假如 f x 得到[],y就不會出現在最左端的
[y | ...],所以相應的x就被篩選掉了。因為最後的 return 是根據收集到的y一個一個執行的。listGuard程式碼當中如果把 return (x, y)改成return x,再把函數的型態做適當修改,把 y <-刪除掉,就是一般的篩選功能了。此時雖然沒有用到y,但是暗中仍是根據收集到的y一個一個執行的。
沒有留言:
張貼留言