Monads: Difference between revisions

From Rosetta Code
Content added Content deleted
m (Spell out a definition of Monad)
(redirect to Category:Monads)
 
(18 intermediate revisions by 3 users not shown)
Line 1: Line 1:
#REDIRECT [[:Category:Monads]]
{{draft task}}
Functional programming [[wp:Monad_(functional_programming)|Monads]] are a mechanism for building types which allow unified handling of more than one underlying type. (This use of this term implies [[wp:Multiple_dispatch|multiple dispatch]], however for [[Rosetta_Code:Add_a_Task#Things_to_avoid|Rosetta Code]] we do not require that this be a feature of the language.)
Demonstrate in your programming language the following:

# Construct a Monad (preferably the Option/Maybe Monad or the List Monad) by making bind and unit for that Monad (or just use what the language already has implemented)
# Make two functions, each which take a number and return a monadic number, e.g. <code>Int -> Maybe Int</code> and <code>Int -> Maybe String</code>
# Compose the two functions with bind

=={{header|Clojure}}==

===Maybe Monad===

<lang clojure>
(defn bind [val f] (if (nil? (:value val)) val (f (:value val))))
(defn unit [val] {:value val})

(defn opt_add_3 [n] (unit (+ 3 n))) ; takes a number and returns a Maybe number
(defn opt_str [n] (unit (str n))) ; takes a number and returns a Maybe string

(bind (unit 4) opt_add_3) ; evaluates to {:value 7}
(bind (unit nil) opt_add_3) ; evaluates to {:value nil}
(bind (bind (unit 8) opt_add_3) opt_str) ; evaluates to {:value "11"}
(bind (bind (unit nil) opt_add_3) opt_str) ; evaluates to {:value nil}
</lang>

===List Monad===

<lang clojure>
(defn bind [coll f] (apply vector (mapcat f coll)))
(defn unit [val] (vector val))

(defn doubler [n] [(* 2 n)]) ; takes a number and returns a List number
(def vecstr (comp vector str)) ; takes a number and returns a List string

(bind (bind (vector 3 4 5) doubler) vecstr) ; evaluates to ["6" "8" "10"]
(-> [3 4 5]
(bind doubler)
(bind vecstr)) ; also evaluates to ["6" "8" "10"]
</lang>

=={{header|J}}==

Note that J documentation mentions "monad" but that is an older (much older) use of the term from what is intended here. J documentation uses "box" <code><</code>to describe the operation mentioned here.

So, here are two functions which each take a number and return a wrapped number:

<lang j>f=: <
g=: <</lang>

And here are the two functions composed together:

<lang j>f@g</lang>

That said J does not, by default, implicitly choose function implementation (which is probably what was implied in this context). But let's wait for the task description to explicitly call for that before trying to address that issue...

=={{header|Ruby}}==

===List Monad===

<lang ruby>
class Array
def bind(f)
map(&f).reduce(:concat)
end
def self.unit(*args)
args
end
end

inc = -> e { Array.unit(e + 1) }
str = -> e { Array.unit(e.to_s) }

Array.unit(3,4,5).bind(inc).bind(str) #=> ["4", "5", "6"]

# Note that inc and str cannot be composed directly,
# as they don't have compatible type signature.
# Due to duck typing (Ruby will happily turn arrays into strings),
# in order to show this, a new function will have to be used:

doub = -> n {[2*n]}
[3,4,5].bind(inc).bind(doub) #=> [8, 10, 12]

# Direct composition will cause a TypeError, as Ruby cannot evaluate 2*[4, 5, 6]
comp = -> f, g {-> x {f[g[x]]}}
[3,4,5].bind(comp[doub, inc]) #=> TypeError: Array can't be coerced into Fixnum

# Composition needs to be defined in terms of bind
class Array
def bind_comp(f, g)
bind(g).bind(f)
end
end

[3,4,5].bind_comp(doub, inc) #=> [8, 10, 12]
</lang>

Latest revision as of 03:29, 1 February 2016

Redirect to: