我學習Haskell的方法我開始掌握monad概念,並開始在代碼中使用已知的monad,但從設計師的角度來看,我仍然遇到難題。在面向對象中有幾個規則,比如「爲名稱標識名詞」,注意某種狀態和接口......但是我無法爲monad找到相應的資源。如何識別monadic設計模式?
那麼如何將自然界中的一個問題確定爲一元問題呢? monadic設計有什麼好的設計模式?當你意識到某些代碼可以更好地重構爲monad時,你的方法是什麼?
我學習Haskell的方法我開始掌握monad概念,並開始在代碼中使用已知的monad,但從設計師的角度來看,我仍然遇到難題。在面向對象中有幾個規則,比如「爲名稱標識名詞」,注意某種狀態和接口......但是我無法爲monad找到相應的資源。如何識別monadic設計模式?
那麼如何將自然界中的一個問題確定爲一元問題呢? monadic設計有什麼好的設計模式?當你意識到某些代碼可以更好地重構爲monad時,你的方法是什麼?
有用的經驗法則是當您在上下文中看到值;單子可以看作是分層的「效果」:
通常情況下,你通常應該從標準Monad Transformer Library分層的單子變壓器設計你的單子,它可以讓你將上面的效果組合成一個單一的模式河畔。它們一起處理您可能想要使用的大部分monad。 MTL中沒有包含一些額外的單子,如probability和supply單子。
至於開發一個新定義的類型是否是一個單子,以及它如何表現爲一個,您可以通過從Functor
到Monad
漲認爲它的一個直覺:
(<*>)
可讓您從嵌入式函數及其嵌入式參數轉到嵌入式結果。明白最簡單的方法是看的join
類型:
join :: (Monad m) => m (m a) -> m a
這意味着,如果你有一個嵌入式計算,其結果是新嵌入式計算,你可以創建執行該計算結果的計算。因此,您可以使用monadic效果根據以前的計算值創建新計算,並將控制流轉移到該計算。
有趣的是,這可以是結構化的東西弱點 monadically:與Applicative
,計算的結構是靜態的(即,一個給定的Applicative
計算具有不能更改基於中間值的影響的一定的結構),而與Monad
它是動態的。這可以限制你可以做的優化;例如,應用解析器不如一元解析器強大(嗯,這不是strictly true,但實際上它是),但它們可以更好地優化。
注意(>>=)
可以定義爲
m >>= f = join (fmap f m)
等單子可以簡單地用return
和join
(假設它被定義是一個Functor
;所有的單子都是合用的函子,但Haskell的類型類層次結構遺憾的是不要求這是historical reasons)。作爲一個補充說明,無論他們從誤導的非Haskellers中得到什麼樣的嗡嗡聲,你可能都不應該過分關注單子。有很多代表有意義和強大模式的類型類,並不是所有的東西都最好用monad表示。 Applicative,Monoid,Foldable ......使用哪種抽象取決於你的情況。當然,僅僅因爲某件事是一個monad並不意味着它不能成爲其他事物;作爲一個monad只是另一種類型的屬性。
所以,你不應該過多地考慮「識別單子」。這些問題更像是:
哦,非常好。如果我沒有睡覺的話,我會寫出很多答案,哈哈。男人,我幾乎不能跟上你們...... – 2012-01-08 18:31:29
@ C.A.McCann:當有代表獲得時,你怎麼能睡覺? :) – ehird 2012-01-08 18:51:33
@ehird +1你最近一直在開發大量的優秀答案。 – 2012-01-08 22:13:58
按照類型。
如果你發現你寫的功能與所有這些類型的
(a -> b) -> YourType a -> YourType b
a -> YourType a
YourType (YourType a) -> YourType a
或所有這些類型的
a -> YourType a
YourType a -> (a -> YourType b) -> YourType b
然後YourType
可以是單子。 (我說「可能」,因爲功能必須服從法律的單子也。)
(請記住,您可以重新排序參數,因此如YourType a -> (a -> b) -> YourType b
只是變相(a -> b) -> YourType a -> YourType b
)
不要看出來只爲單子!如果你把所有這些類型的
YourType
YourType -> YourType -> YourType
的功能,他們遵守法律幺,你有一個幺!這也可能是有價值的。對於其他類型類也是如此,最重要的是Functor。
有單子的效果圖:
一旦你熟悉了這些影響其容易建立單子他們單子變壓器相結合。請注意,組合一些單子需要特別的照顧(特別是Cont和具有回溯的單子)。
有一件重要的事情要注意的是沒有太多單子。有一些外來的不在標準庫中,例如概率monad和Cont monad的變體如Codensity。但是除非你正在做一些數學上的事情,否則你會發明(或發現)一個新的monad,但是如果你使用Haskell足夠長的時間,你將會創建許多不同的標準monad組合。
編輯 - 另請注意,爲了您堆疊在不同的單子單子變壓器結果:
如果添加ErrorT(變壓器)的作家單子,你得到這個單子Either err (log,a)
- 你只能訪問日誌,如果你沒有錯誤。
如果您將WriterT(transfomer)添加到Error monad,您會得到此monad (log, Either err a)
,它總是可以訪問日誌。
這是一種無法回答的問題,但我覺得反正說很重要。 只問! StackOverflow,/ r/haskell和#haskell irc頻道都是獲得智能人員快速反饋的好地方。如果你正在研究一個問題,並且你懷疑有一些monadic的魔法可以使它更容易,那就問問! Haskell社區喜歡解決問題,並且是非常友好的。
不要誤會,我不鼓勵你永遠不要爲自己學習。恰恰相反,與Haskell社區互動是其中一種學習方式。 LYAH和RWH,2個免費在線提供的Haskell書籍,也強烈推薦。
呵呵,別忘了玩,玩,玩!當你使用monadic代碼玩耍時,你會開始感覺到「形狀」monad有什麼樣的感覺,以及monadic combinators是否有用。如果你正在推出自己的monad,那麼通常類型系統會引導你一個明顯的,簡單的解決方案。但說實話,你應該很少需要推出你自己的Monad實例,因爲Haskell庫提供了其他答案者提到的大量有用的東西。
這個問題「這個問題應該單獨解決」,還有更多「這個問題應該用[某些數據類型]來解決,嘿!多麼方便,[這個數據類型]是Monad的一個實例,給我噸合作的可組合性。「 – 2012-01-08 22:12:04
@DanBurton:無論是面向對象,程序,功能,回溯邏輯,連接還是任何其他類型的語言,當然都可以採用任何其他類型的設計模式。 – 2012-01-10 12:55:41