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

发布于 2024-11-04 21:06:08 字数 1431 浏览 2 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

帅气称霸 2024-11-11 21:06:08

Clojure 不是静态类型的,因此不需要 haskell(以及我认为 Scala)中必需的严格的 this/that/whatever 类型声明。如果要返回字符串就返回字符串;如果你返回 nil ,那也没关系。

“函数式”并不完全对应于“严格的编译时类型”。它们是正交的概念,Clojure 选择动态类型。事实上,很长一段时间我都无法想象如何实现许多高阶函数,例如 map 并仍然保留静态类型。现在我对 Haskell 有了一点(非常少)的经验,我可以看到这是可能的,而且实际上通常非常优雅。我怀疑,如果您使用 Clojure 一段时间,您将会有相反的体验:您会意识到类型声明对于为您提供您习惯拥有的那种功能来说并不是必需的用函数式语言。

Clojure is not statically typed, so doesn't need the strict this/that/whatever type declarations that are necessary in haskell (and, I gather, Scala). If you want to return a string, you return a string; if you return nil instead, that's okay too.

"Functional" does not correspond exactly to "strict compile-time typing". They are orthogonal concepts, and Clojure chooses dynamic typing. In fact, for quite some time I couldn't imagine how you could implement many of the higher-order functions like map and still preserve static typing. Now that I have a little (very little) experience with Haskell, I can see that it's possible, and indeed often quite elegant. I suspect that if you play with Clojure for a while, you will have the opposite experience: you'll realize the type declarations aren't necessary to give you the kind of power you're used to having in a functional language.

十年不长 2024-11-11 21:06:08

在 Clojure 中,nil 双关语提供了 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 的 Maybe 都是 Applicative 的实例。这意味着您可以在推导式中使用这些类型的值。例如,Scala 支持:

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

Clojure 的 for 宏提供对 seq 的理解。与一元推导式不同,此实现允许混合实例类型。

尽管 Clojure 的 for 不能用于在多个可能的 nil 值上组合函数,但它的功能实现起来很简单。

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

并称其为:

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

In Clojure, nil punning provides most of the functionality that Scala & Haskell get from Option & Maybe.

**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's Option & Haskell's Maybe are both instances of Applicative. This means that you can use values of these types in comprehensions. For example, Scala supports:

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

Clojure's for macro provides comprehensions over seq. Unlike monadic comprehensions, this implementation allows mixing instance types.

Though Clojure's for can't be used for composing functions over multiple possible nil values, it's functionality that's trivial to implement.

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

And calling it:

(appun + 1 2 3)    #_=> 6
(appun + 1 2 nil)  #_=> nil
樱花落人离去 2024-11-11 21:06:08

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

是关于组合的,这是我们认为非常重要的事情。在每种编程语言中,Monad 每天都会跟踪一些有关正在发生的事情的“额外上下文”……可以将其想象为一个保存当前值的盒子,可以将函数应用于该值。额外的上下文可以演变为 。

Maybe 类型是将长的计算序列链接在一​​起,而不必谈论任何有关失败的内容(这是“额外的上下文”),这是一种将“错误处理”移出计算的模式 你可以在 Maybe 上串入一系列计算,一旦其中一个失败,其余的就会被忽略,最终结果是“无”。如果它们都成功,那么你的最终结果就是保存结果值的 monad。这

允许您编写这样的代码:少了很多纠缠。

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

It is important to remember that the Monad concept is not about types! Type systems help you enforce the rules (but even Haskell cannot enforce all of the rules, since some of them (the Monad Laws) are cannot be fully expressed by a type system.

Monads are about composition, which is a very important thing that we all do every day in every programming language. In all cases, the Monad tracks some "extra context" about what is going on...think of it like a box that holds onto the current value. Functions can be applied to this value, and the extra context can evolve as an orthogonal concern.

The Maybe type is about chaining long sequences of computation together while not having to say anything at all about failure (which is the "extra context"). It is a pattern that moves the "error handling" out of the computation and into the Monad. You can string a sequence of computations on a Maybe and as soon as one fails, the rest are ignored and the final result is "nothing". If they all succeed, then your final result is the monad holding the result value.

This allows you to write code that is much less entangled.

Clojure supports Monads, as @deterb pointed out.

葬心 2024-11-11 21:06:08

Maybe/Option 是一种类型。它与函数式编程无关。是的,一些语言(Scala、haskell、ocaml)除了功能之外还提供了非常强大的类型系统。人们甚至说 Haskell 是一种带有类型的编程。

其他语言(clojure、lisp)在类型方面没有提供太多功能,尽管它们是功能齐全的函数式语言。他们的侧重点不同,而且 Maybe/Option 类型不适合。它根本无法提供动态语言的太多信息。例如,许多对序列(列表、向量、映射)进行操作的 clojure 函数将完全接受 null (nil) 并将其视为空结构。

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

Clojure 不能被称为“使用类型编程”,因此 Maybe type 在其中没有多大意义。

Maybe/Option is a type. It has nothing to do with functional programming. Yes, some languages (Scala, haskell, ocaml) besides being functional also provide a very powerful type system. People even say about haskell that it is a programming WITH TYPES.

Others (clojure, lisp) do not provide much in terms of types even though they are fully capable functional languages. Their emphasis is different, and Maybe/Option type does not fit in. It simply does not give you much in dynamic language. For example many clojure functions operating on sequences (lists, vectors, maps) will perfectly accept null (nil) and treat it as empty structure.

(count nil) will give you 0. Just like (count [])

Clojure cannot be called a "programming with types" and thus Maybe type does not make much sense in it.

听风吹 2024-11-11 21:06:08

好吧,有一个 Maybe monad,但它使用 nil 作为 Nothing,仅捕获计算的抽象(如果 input=nil 返回 nil else calc 任何输入)以避免空指针错误,但它没有静态编译时安全。还有 fnil 也有类似的使命,用默认值和 修补 nil -?>。我认为 clojure 方式更倾向于返回引发错误或 nil 的默认值。

Well there is a Maybe monad but it uses nil as Nothing, capturing only the abstraction of computation (if input=nil return nil else calc whatever with input)to avoid null pointers errors but it doesnt have the static compile-time safety. There is fnil too that have a similar mission, patching nil with default values and a -?>. I think the clojure way is more oriented to return default values that raise errors or nil.

年少掌心 2024-11-11 21:06:08

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

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

我快速浏览了 Clojure-Contrib 库,他们有一个 monad 包 您可能想看看。另一件真正让我了解如何在 Clojure 中使用 Monad 的项目是 Cosmin 关于 Monad 的教程在 Clojure 中。正是这一点帮助我联系了如何在 Scala 中更明确地声明功能作为动态 Clojure 语言的一部分进行处理。

Going with @amalloy and comments that Clojure, as a language, doesn't have a need for an optional return value.

I haven't done much with Scala, but Clojure doesn't need to know the strict details about the return type to be able to work with a value. It's almost as if a Maybe monad was embedded and made a part of normal Clojure evaluation, as many of the operations, if performed on nil, return nil.

I took a quick look at the Clojure-Contrib library, and they have a monad package which you may want to look at. Another item which really clued me into how one would make use of Monads in Clojure, is Cosmin's tutorial on Monads in Clojure. It was this that help me connect how the functionality that is stated more explicitly in Scala is handled as part of the dynamic Clojure language.

原来是傀儡 2024-11-11 21:06:08

从 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-> 函数提供 Option[T ]。

There is some-> and some->> available since Clojure 1.5

(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)

The some-> function is providing the Option[T].

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文