algo.monads

maybe-m breaks the monad laws.

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Completed
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

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?))
nil

user=> (nil? nil)
true

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.

Activity

Hide
Seth J. Gold added a comment -

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?)))
nil
user=> (with-monad maybe-m ((comp m-result nil?) nil))
true

Show
Seth J. Gold added a comment - 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?))) nil user=> (with-monad maybe-m ((comp m-result nil?) nil)) true
Hide
Bruno Tavares added a comment -

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

Show
Bruno Tavares added a comment - 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))))
Hide
Konrad Hinsen added a comment -

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.

Show
Konrad Hinsen added a comment - 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.
Konrad Hinsen made changes -
Field Original Value New Value
Resolution Completed [ 1 ]
Status Open [ 1 ] Closed [ 6 ]

People

Vote (0)
Watch (2)

Dates

  • Created:
    Updated:
    Resolved: