簡體   English   中英

單子 vs. 箭頭

[英]Monads vs. Arrows

我對函數式編程中使用的monad箭頭的概念非常熟悉。 我也明白它們可以用來解決類似的問題。

但是,對於在任何給定情況下如何選擇使用哪個,我仍然有些困惑。

什么時候應該使用 monad,什么時候應該使用箭頭?

Lindley、Wadler 和 Yallop 發表了兩篇出色的論文(在 LTU此處討論)。

需要理解的最重要的事情是,有更多的東西是比箭有東西是單子。 相反,monad 嚴格來說比箭頭更強大( 上面第二篇論文精確地指定了哪種方式)。

特別是,monad 是配備了類型為(a ~> b, a) ~> b的 apply 函數的箭頭,其中(~>)是給定箭頭的構造函數。 林德利等人。 指出這破壞了箭頭在術語和命令(或者,如果您願意,對象和態射)之間保持的細致區分。

應用函子有廣泛的應用,特別是對於那些最好被認為是對流的操作的東西。 事實上,人們可以將箭頭看作是在流上推廣轉換器的概念(即,為由給定的應用函子構造的對象上的態射引入一種新語言)。

根據我的經驗,由於 monad 模糊了對象和態射之間的區別(即,如果我正確使用了這些詞,則會產生一個封閉的笛卡爾范疇),那么 monad 中的術語通常比一個箭頭或應用函子(盡管請注意,兩者都允許您分別通過arrpure方法注入任意函數)。

因此,如果某些東西沒有被賦予 monad 的特征(即使在概念上它形成了一個),那么它就有可能接受更多的檢查和優化。 序列化也可能更容易。 因此在解析器和電路建模中使用了應用程序和箭頭。


以上試圖是一般性和描述性的。 以下是我的一些自以為是的經驗法則。

如果您需要對看起來像狀態的東西進行建模,請從 monad 開始。 如果您需要對看起來像全局控制流(即異常、延續)的東西進行建模,請從 monad 開始。 如果出現與 monad 的功能和通用性相沖突的需求(即對於哪個 join (join :: m (ma) -> ma)過於強大),那么請考慮削弱您正在使用的東西的功能。

如果您需要對流和流上的轉換進行建模,特別是某些特征(尤其是過去和未來的無限視圖)應該是不透明的流,那么從應用函子開始。 如果您需要對流上的轉換屬性進行更深入的推理,請考慮使用箭頭。

或者,非常粗略地說,applicative 用於電路的動作,箭頭用於電路的結構,而 monad 用於通用計算效果。

當然還有更多的故事。 對於應用程序,請特別參閱Conal Elliott 在 FRP方面的工作 對於箭頭,請參閱HXT XML 解析器庫Yampa FRP 項目Haskell on a Horse Web 框架、Hudak 和 Liu 的經典文章 “用箭頭堵塞空間泄漏”等。 對於 monad,請查看任何地方。 當然,請注意,僅僅因為某物是 monad,並不意味着應用符號可能不會更清晰和更具表現力。

簡短的回答是 Arrows 比 Monads 更通用,而且使用起來也更麻煩。 因此,您應該盡可能使用 Monads,在 Monads 不適用的情況下使用 Arrows。

“風景路線”的答案如下。

介紹 Arrows 的人 John Hughes 發表了兩篇我推薦的偉大論文: “將單子推廣到箭頭”“用箭頭編程” 這兩篇文章易於閱讀,並為您的問題提供了答案。 即使有些人不理解這兩篇文章中的所有細節或代碼,他們肯定會找到很多關於 Monads 和 Arrows 的信息和非常有用的解釋。

我現在將強調這些文章中與您的問題有關的要點

當 Monads 被引入時,人們認為它們是無所不能的。 確實,Monads 具有強大的功能。 但是到了某個時候,發現有些情況下,Monads 是不能應用的。 這些情況與多個輸入有關,尤其是當某些輸入是靜態的而某些輸入是動態的時。 因此,約翰·休斯(John Hughes)挺身而出,介紹了 Arrows。

箭頭比 Monad 更通用。 箭頭是 Monad 的超集。 他們可以完成 Monad 所做的一切,甚至更多。 但它們也更難使用。 John Hughes 建議你應該盡可能使用 Monads,當你不能使用 Monads 時應該使用 Arrows。

我同意約翰休斯的觀點。 我還想起了愛因斯坦的名言“一切都應該盡可能簡單,但不能更簡單”。

當然,這一切都取決於手頭的特定情況。 讓我解釋一下。 讓我們假設您正在學習 Haskell。 然后使用一元方法完成每個程序並使用基於箭頭的方法重做它將是一項偉大的任務。 在學習的時候,你應該努力探索所有的可能性,實現各種方法。 通過這種方式,您可以獲得深刻的洞察力,並且能夠直接比較不同的解決方案。

現在讓我們假設您想向社區提供一個庫。 好吧,您應該感謝會閱讀您代碼的人,您應該使用最容易理解的方法並且仍然可以完成工作。 您還應該感謝將使用您的代碼的人,您的解決方案缺乏不必要的復雜性。 這樣,您的解決方案更易於維護,並且更不容易出錯和出錯。

但是,如果您處於邊緣情況怎么辦? 讓我們假設您不確定是否需要 Arrows 的額外力量。 那你應該怎么做? 您是否應該從一元方法開始,然后在需要時切換到基於箭頭的方法? 還是應該從一開始就使用 Arrows,避免在項目中途進行昂貴的轉換?

同樣,我的答案是嘗試第一種方法:如果可以,嘗試使用 Monads。 如果你后來發現你不能使用 Monads,你將不得不忍受代價高昂的轉換,你必須重新啟動並重做項目才能使用 Arrows。 這種方法肯定需要您提供更多的時間和其他資源。 但是你會知道你做了正確的事情,那就是試圖提供最簡單、最清晰、最簡單的解決方案。

避免不必要的復雜性是最重要的。 信不信由你,這就是將范疇論中的概念(例如函數組合、Monads 和 Arrows)引入計算機科學的原因。 諷刺?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM