为什么在Clojure中使用Maybe / Option并不是那么普遍?

时间:2011-04-30 05:08:19

标签: functional-programming clojure option monads maybe

为什么Clojure尽管如此强调功能范式,却不使用Maybe / Option monad来表示可选值? Option的使用在Scala中非常普遍,Scala是我经常使用的函数式编程语言。

7 个答案:

答案 0 :(得分:45)

Clojure不是静态类型的,因此不需要严格的this / that / haskell中必需的任何类型声明(并且,我收集,Scala)。如果要返回一个字符串,则返回一个字符串;如果你改为nil,那也没关系。

“功能”与“严格编译时键入”并不完全对应。它们是正交概念,Clojure选择动态类型。事实上,很长一段时间以来我无法想象如何实现许多高阶函数,如map,并仍然保留静态类型。现在我对Haskell有一点(非常少)的经验,我可以看到它是可能的,而且确实经常非常优雅。我怀疑如果你玩Clojure一段时间,你会有相反的经历:你会意识到类型声明不是必要给你一种你习惯拥有的力量用函数式语言。

答案 1 :(得分:22)

在Clojure中,nil punning提供了Scala& amp;的大部分功能。 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可能都是Applicative的实例。这意味着您可以在理解中使用这些类型的值。例如,Scala支持:

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

宏观的Clojure提供了对seq的理解。与monadic理解不同,此实现允许混合实例类型。

虽然Clojure不能用于在多个可能的nil值上编写函数,但它的功能实现起来很简单。

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

并称之为:

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

答案 2 :(得分:15)

重要的是要记住,Monad概念与类型无关!类型系统可以帮助您实施规则(但即使是Haskell也无法强制执行所有规则,因为其中一些规则(Monad Laws)无法通过类型系统完全表达。

Monads是关于组合的,这是我们每天在每种编程语言中都做的非常重要的事情。在所有情况下,Monad跟踪一些关于正在发生的事情的“额外背景”......把它想象成一个保持当前价值的盒子。函数可以应用于此值,额外的上下文可以演变为正交关注点。

Maybe类型是关于将长序计算链接在一起而不必对失败说什么(这是“额外的上下文”)。这是一种将“错误处理”从计算中移出并进入Monad的模式。你可以在一个Maybe上串起一系列的计算,一旦失败,其余的都被忽略,最后的结果是“什么都没有”。如果它们都成功,那么你的最终结果是monad保持结果值。

这使您可以编写更少纠缠的代码。

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

答案 3 :(得分:12)

可能/选项是一种类型。它与函数式编程无关。是的,除了功能之外,一些语言(Scala,haskell,ocaml)也提供了一个非常强大的类型系统。人们甚至会说haskell这是一个有类型的编程。

其他(clojure,lisp)在类型方面提供的内容并不多,即使它们是完全有能力的函数式语言。他们的重点是不同的,并且可能/选项类型不适合。它只是不会给你很多动态语言。例如,对序列(列表,向量,映射)进行操作的许多clojure函数将完全接受null(nil)并将其视为空结构。

(count nil)会给你0.就像(count [])

Clojure不能称为“带类型的编程”,因此可能类型在其中没有多大意义。

答案 4 :(得分:7)

答案 5 :(得分:4)

使用@amalloy并评论Clojure作为一种语言,不需要可选的返回值。

我对Scala没有做太多,但Clojure不需要知道有关返回类型的严格细节,以便能够使用值。这几乎就像是一个Maybe monad被嵌入并成为正常Clojure评估的一部分,因为许多操作(如果在nil上执行)返回nil

我快速浏览了Clojure-Contrib库,他们有一个monad package你可能想看一下。另一个真正让我了解如何在Clojure中使用Monads的项目是Cosmin's tutorial on Monads in Clojure。正是这一点帮助我将如何在Scala中更明确地陈述的功能作为动态Clojure语言的一部分进行处理。

答案 6 :(得分:1)

自Clojure 1.5以来有some->some->>

(let [input {:a 1 :b 2 :c {:d 4 :e 5 :f {:h 7}}}]
  (some-> input :c :f :h inc))
user> 8

(let [input {:a 1 :b 2 :c {:d 4 :e 5 :f {:h 7}}}]
  (some-> input :c :z :h inc))

user> nil

(let [input {:a 1 :b 2 :c {:d 4 :e 5 :f {:h 7}}}]
  (-> input :c :z :h inc))

user> NullPointerException   clojure.lang.Numbers.ops (Numbers.java:1013)

some->函数提供选项[T]。