Why is the use of Maybe/Option not so pervasive in Clojure?

两盒软妹~` 提交于 2019-12-18 10:32:33

问题


Why does Clojure, despite such an emphasis on functional paradigm, not use the Maybe/ Option monad to represent optional values? The use of Option is quite pervasive in Scala, a functional programming language I use regularly.


回答1:


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.




回答2:


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



回答3:


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.




回答4:


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.




回答5:


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.




回答6:


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.




回答7:


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].



来源:https://stackoverflow.com/questions/5839697/why-is-the-use-of-maybe-option-not-so-pervasive-in-clojure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!