<< Back to previous view

[ALGOM-7] maybe-m breaks the monad laws. Created: 15/Sep/12  Updated: 05/Feb/14  Resolved: 05/Feb/14

Status: Closed
Project: algo.monads
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Seth J. Gold Assignee: Konrad Hinsen
Resolution: Completed Votes: 0
Labels: None


One of the monad laws is that (m-bind (m-result v) f) should be the same as (f v). However, this is not the case in maybe-m:

user=> (with-monad maybe-m (m-bind (m-result nil) nil?))

user=> (nil? nil)

The crux of the problem is that in algo.monad's maybe-m, there is no way to wrap a nil in a Just-like container.

Comment by Seth J. Gold [ 15/Sep/12 3:27 PM ]

Just realized that that demonstration doesn't actually work, because the function passed to m-bind is supposed to return a monadic value. Here's a better one:

user=> (with-monad maybe-m (m-bind (m-result nil) (comp m-result nil?)))
user=> (with-monad maybe-m ((comp m-result nil?) nil))

Comment by Bruno Tavares [ 07/Jun/13 8:51 PM ]

I don't think this would be a valid example.

Here is an example in Haskell
Nothing >>= \x -> Just(x / 0) – => Nothing

; Clojure example
(with-monad maybe-m (m-bind m-zero #(/ % 0))) ; => nil
(with-monad maybe-m (= m-zero nil)) ; => true

;; Both examples will fail
(with-monad maybe-m (#(/ % 0) m-zero))
(with-monad maybe-m ((comp m-result #(/ % 0)) m-zero))

Those errors would not be possible to happen with Haskell's type system.

The following snippet shows it evaluates properly the monadic bind law for valid operations

(let [value 1
operation #(+ % 1)]
(with-monad maybe-m
(m-bind (m-result value) operation)
(operation value))))

Comment by Konrad Hinsen [ 05/Feb/14 5:20 AM ]

The Clojure implementation of maybe-m is based on the convention that nil is not a value, but a marker for "not a value". That's a very common convention in Clojure, so from a practical point of view this is the most useful way to implement maybe-m.

There are other options, and everyone is invited to implement their personal preference and use it in place of maybe-m. For example, a monadic value could be either an empty list or a list containing a single value.

Note that the Haskell approach of setting up a special type for the maybe-m container is not an option in a dynamically typed language. Whatever you choose to represent "no value" can be created outside of the monad and thus be used to violate the monad laws. It must be understood that the monad laws are valid only subject to the conventions of the specific monad.

Generated at Fri Feb 12 22:46:20 CST 2016 using JIRA 4.4#649-r158309.