Haskell的>>是如何實現的?如果是\_->i d,那第一個參數豈不是會因為惰性求值而不被求值?

比如說,假設我有(這是我根據直覺腦補的)

(&>&>) _ = id

那麼它左邊那個參數就不需要求值了,因為對結果(看起來)沒有影響,我也想過

(&>&>) () = id

這樣它可能會因為模式匹配而消耗掉左邊的()讓副作用成功執行,但我如果是其他的裡面不是()的Monad又怎麼辦呢?


首先 (&>&>) 是Moand typeclass中的一個函數,具體instance時可以定義其實現。默認實現是:

(&>&>) :: forall a b. m a -&> m b -&> m b

m &>&> k = m &>&>= \_ -&> k

還是得提一下Monad並不是副作用的代言詞,Monad只是在自函子範疇上的一個幺半群。畢竟除了IO Monad還有Maybe Monad等等和副作用無關的存在。當你在Haskell中考慮副作用的時候你其實就脫離了純函數式範式。

IO Monad的具體實現在http://hackage.haskell.org/package/base-4.10.0.0/docs/src/GHC.Base.html#line-1173


m1 &>&> m2 = m1 &>&>= const m2

====以上為原答案====

題主給的函數能通配a -&> b -&> b,而(&>&>)的簽名是m a -&> m b -&> m b,沒把Monad m限制(class下的函數)用起來,肯定是不對的。m b裡面可能封裝了更多信息,而不是只有b類型的值,不能認為一個m b類型的值只能由另一個m b構造,或者認為m a求出來的值肯定要扔。

有回答提到了Monad並不是副作用的代言詞。不講數學意義的話,可以想像成它封裝了作用,而不是副作用。對print "a" :: IO ()求值是pure的,它的值是」把a列印出來「這個作用,求值並不會實際列印任何東西。其他Monad也同理。

不恰當地比喻一下IO,想像IO a存了一段最終返回類型a的指令,(&>&>) :: m a -&> m b -&> m b的實現就是把一段指令後面連上另一段指令,合併後的指令執行結果為後者結果,但並不代表m a的指令全都扔了,指令是要運行的,但結果a沒用上而已。求值main得到一大大大段指令(當然由於lazy,不會也不能一次性全部求出),至於如何/何時執行指令,那不是語言層面要管的事。


推薦閱讀:

將 Haskell 翻譯為 Rust, C# (上)標準庫
Haskell有多少跟State/Reference有關的東西?
Rust相較於Haskell有何優勢?

TAG:編程 | 函數式編程 | Haskell | 惰性求值 |