Monads: Difference between revisions

From Rosetta Code
Content added Content deleted
(J: update to be const with current task definition)
(redirect to Category:Monads)
 
(13 intermediate revisions by 2 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 and hides [[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 [[wp:Monad_(linear_algebra)|older]] ([[wp:Monad_(music)|much older]]) use of the term from what is intended here. J documentation uses "box" <code><</code>to describe the operation mentioned here.

That said, here is an implementation which might be adequate for the current task description:

<lang J>bind=: S:0
unit=: boxopen

m_num=: unit
m_str=: unit@":</lang>

Task example:

<lang J> m_str bind m_num 5
┌─┐
│5│
└─┘</lang>

=={{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: