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.

- 12,568
- 8
- 34
- 67

- 90,905
- 62
- 285
- 365
-
2I am going to point to Daniel's excellent answer on why Scala uses Option[T]; maybe the answers should read it first. - http://stackoverflow.com/questions/2079170/why-optiont/2079758#2079758 – Eugene Yokota Apr 30 '11 at 17:47
-
This talk by Rich Hickey might give the most definitive answer: https://www.youtube.com/watch?v=YR5WdGrpoug. The talk is titled "Maybe Not" and Rich discusses the reasons why `Maybe` or `Option` don't make the most semantic sense as they are implemented in Haskell, for instance. – Jeel Shah Jul 31 '19 at 17:18
7 Answers
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.

- 89,153
- 8
- 140
- 205
-
6You probably didn't get my question. My question has absolutely nothing to do with type declarations. – missingfaktor Apr 30 '11 at 06:10
-
5In my experience, `Maybe`/`Option` is useful regardless of whether the language in question is statically typed or dynamically typed. – missingfaktor Apr 30 '11 at 06:11
-
28@missingfaktor: No, I think amalloy has a point—dynamically typed languages often use some value (such as `nil`) to represent "no such thing", but this value is of a different type (in Scheme, it's a list; in Ruby, it's the only instance of `NilClass`; I've never used Clojure, but I imagine it's like Scheme in this regard). Without the static type system, there's no need to lift the result into `Maybe`; that's implicit, so to speak. I personally tend to prefer the way Haskell/Scala does it, but there's nothing wrong with the other approach in a dynamically typed language. – Antal Spector-Zabusky Apr 30 '11 at 11:09
-
1Clojure has a focus on atomic pieces of usefulness, having just read up on that the kinds of things that Maybe/Option provide, it seems to me that there are many concerns to be addressed with Maybe/Option that get more specific treatments in Clojure. – animal Apr 30 '11 at 17:58
-
@Antal - Clojure is less like Scheme and more like Common Lisp in the sense that is uses nil for "no such thing" – mikera May 09 '11 at 11:56
-
You can very helpfully use the Maybe monad in Javascript, it has nothing to do with static typing: https://jrsinclair.com/articles/2016/marvellously-mysterious-javascript-maybe-monad/ – Nowhere man Sep 17 '19 at 08:28
-
@Nowhereman realize this is a couple of years old but... no. Not really. There is no Maybe monad in Javascript. Monads are a *type-level concept*, they don't really have a term-level reification. You can't even really do the Maybe monad in *Typescript*, because the language lacks proper sum types. That's not to say that JS or TS are *bad*, or that sum types are *good*, just that the concepts don't totally transpose. The article you link does as good a job as it's possible to do in JS a la fantasyland, but it isn't really the same thing. – Jared Smith Jun 06 '23 at 17:58
-
@JaredSmith what exactly can't be done in TypeScript? I've seen monad libraries in JS and in some I didn't spot anything missing in the features that make a monad. – Nowhere man Jul 14 '23 at 19:26
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

- 437
- 4
- 7
-
The Maybe monad makes the nil punning outside functions, which makes you free to write and use functions that presume they received valid arguments. So nil punning in itself is very far from providing most of the functionality of the Maybe monad. – Nowhere man Sep 17 '19 at 08:30
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.

- 5,535
- 23
- 27
-
Finally, an explanation of Monads without having to first understand category theory. This is truly what Monads are all about. It's a shame most attempts at explanation obfuscate this with arcane mathematics. – Brennan Cheung Jun 14 '17 at 23:04
-
Your point about Maybe being primarily about error handling uncovers another thought. Perhaps the reason why the Maybe type is not as ubiquitous as in other functional languages is because Clojure doesn't eschew throwing Exceptions as a form of error handling, which often accomplishes the same result as chaining a bunch of Mondads together. – jmrah Jan 09 '21 at 18:35
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.

- 4,816
- 1
- 26
- 31
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.

- 944
- 10
- 18
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.
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].

- 83
- 6
-
1Your answer could be improved by giving a little blurb about what some-> and some->> do, and perhaps what clojure 'pattern' they replace. – jmrah Jan 09 '21 at 18:28