2011-04-30 53 views
37

爲什麼Clojure儘管如此強調功能範例,卻不使用monad來表示可選值?在我經常使用的函數式編程語言Scala中,使用Option相當普遍。爲什麼在Clojure中Maybe/Option的使用不那麼普遍?

+2

我要指出丹尼爾爲什麼選擇Scala使用Option [T]的優秀答案;也許答案應該先閱讀它。 - http://stackoverflow.com/questions/2079170/why-optiont/2079758#2079758 – 2011-04-30 17:47:37

回答

45

Clojure不是靜態類型的,所以不需要嚴格的haskell(以及我收集的Scala)中必需的this/that /任何類型的聲明。如果你想返回一個字符串,你會返回一個字符串;如果你返回零,相反也沒關係。

「功能」並不完全對應於「嚴格編譯時鍵入」。它們是正交的概念,Clojure選擇動態類型。事實上,相當長一段時間,我無法想象如何實現map等更高階的函數,並仍保留靜態類型。現在我對Haskell有一點(非常少的)經驗,我可以看到它是可能的,而且通常非常優雅。我懷疑,如果你在Clojure上玩了一段時間,你會有相反的經歷:你會意識到類型聲明不是必需的給你一種功能語言的權力。

+5

你可能沒有得到我的問題。我的問題與類型聲明完全無關。 – missingfaktor 2011-04-30 06:10:28

+3

根據我的經驗,無論所討論的語言是靜態類型還是動態類型,'Maybe' /'Option'都很有用。 – missingfaktor 2011-04-30 06:11:21

+27

@missingfaktor:不,我認爲amalloy有一個點動態類型化語言經常使用某些值(如'nil')來表示「沒有這樣的事情」,但是這個值是不同的類型(在Scheme中,它是一個列表;在Ruby中,它是'NilClass'的唯一實例;我從來沒有使用過Clojure,但我想像這就像Scheme一樣)。沒有靜態類型系統,就沒有必要將結果提升到「可能」;這是隱含的,可以這麼說。我個人傾向於更喜歡Haskell/Scala的方式,但動態類型語言中的另一種方法沒有任何問題。 – 2011-04-30 11:09:46

12

也許/選項是一種類型。它與函數式編程無關。是的,一些語言(斯卡拉,哈斯克爾,ocaml)除了功能性也提供了一個非常強大的類型系統。人們甚至會說haskell它是一種帶有類型的編程。

其他(clojure,lisp)儘管它們是功能完備的語言,但它們的類型並不多。他們的重點是不同的,而Maybe/Option類型不適合。它在動態語言中根本不會給你太多。例如,對序列(列表,向量,地圖)進行操作的許多clojure函數將完全接受null(nil)並將其視爲空結構。

(計數爲零)會給你0。就像(計數[])

的Clojure不能被稱爲「編程與類型」,因而也許類型沒有太大的意義在裏面。

7

以及有一個也許單子,但它使用的零如無物,捕捉只有計算的抽象(如輸入=零返回nil其他計算任何與輸入),以避免空指針錯誤,但它沒有靜態編譯時間安全。還有fnil也有類似的任務,修補零缺省值和-?>。我認爲clojure方式更傾向於返回引發錯誤或零的默認值。

4

與@amalloy一起發表評論,作爲一種語言,Clojure不需要可選的返回值。

我對Scala並沒有做太多的工作,但Clojure並不需要知道返回類型的嚴格細節,以便能夠使用值。就好像一個Maybe monad被嵌入並且成爲正常Clojure評估的一部分,因爲如果在nil上執行許多操作,則返回nil

我快速瀏覽了Clojure-Contrib庫,他們有一個monad package,你可能想看看。另一個真正讓我知道如何在Clojure中使用Monad的項目是Cosmin's tutorial on Monads in Clojure。正是這樣才能幫助我將Scala中更明確地陳述的功能作爲動態Clojure語言的一部分進行處理。

20

在Clojure中,nil punning提供了Scala & Haskell從Option &獲得的大部分功能。

**Scala**    **Clojure** 
Some(1) map (2+_)  (if-let [a 1] (+ 2 a)) 

Some(1) match {   (if-let [a 1] 
    case Some(x) => 2+x  (+ 2 a) 
    case None => 4  4) 
} 

Scala的選項& Haskell的也許是應用型的兩個實例。這意味着你可以在理解中使用這些類型的值。例如,Scala支持:

for { a <- Some(1) 
     b <- Some(2) 
} yield a + b 

Clojure's for macro提供對seq的理解。與monadic理解不同,這個實現允許混合實例類型。

雖然Clojure的for不能用於在多個可能的nil值上編寫函數,但它的功能很簡單。

(defn appun [f & ms] 
    (when (every? some? ms) 
    (apply f ms))) 

,把它:

(appun + 1 2 3) #_=> 6 
(appun + 1 2 nil) #_=> nil 
10

重要的是要記住,單子概念是不是類型是很重要的!類型系統可以幫助你執行規則(但即使Haskell也不能執行所有的規則,因爲它們中的一些(Monad定律)不能被類型系統完全表達出來)

Monads是關於構圖,這是一個非常在所有情況下,Monad都會跟蹤一些關於正在發生的事情的「額外上下文」......把它想象成一個盒子,可以保存當前值。到這個值,並且額外的上下文可以作爲一個正交的關注點演化

Maybe類型是關於將長序列的計算串聯在一起,而不必對失敗(這是「額外的上下文」)做任何說明。這是一種將「錯誤處理」移出計算的模式並進入Monad。你可以在一個Maybe上對一系列計算進行串聯,只要一個失敗,其餘的都會被忽略,最終的結果就是「無」。如果他們都成功了,那麼你的最終結果就是擁有結果值的monad。

這使您可以編寫糾纏得更少的代碼。

Clojure支持Monads,正如@deterb指出的那樣。

+0

最後,Monad的解釋不需要先理解類別理論。這確實是Monad的全部內容。這是一個恥辱的大多數嘗試解釋混淆這與奧術數學。 – 2017-06-14 23:04:44

相關問題