Category:Monads: Difference between revisions

From Rosetta Code
Content added Content deleted
(Move Monads to Category:Monads)
 
m (Not a task, its a category.)
 
(16 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{draft task}}
In functional programming, the [[wp:Monad_(functional_programming)|Monad]] pattern is a general solution to the problem of nesting (or 'composing') functions when the data to which they apply is enclosed in some kind of useful wrapping. It involves implementing two higher-order functions which, between them, can take care of ensuring that the nested (data-transforming) functions are not choked by being called on unexpected types of data. (Wrapped data, when they were expecting something raw and unwrapped).


In functional programming, the [[wp:Monad_(functional_programming)|Monad]] design pattern is a general solution to the problem of nesting (or 'composing') a class of functions which enclose their output values in some kind of useful wrapping. The output envelope might, for example, contain, in addition to the returned value, a log string, or a boolean indicator of whether or not the input was a legal value. Sometimes the output might simply be enclosed in a list representing a range of possible values rather than a single value.
The two higher-order functions which make up the monad pattern handle the details of: 1. wrapping and unwrapping data, and 2. Providing other functions with direct access to the unwrapped data contents. Delegating the mechanics to these two meta-functions allows the programmer to work with a simple and well-understood generic model, and to nest functions transparently.


Functions of this type can not be directly nested with each other, because their output type (wrapped) does not match their input type (raw and unwrapped).
The two monad functions are sometimes named as follows:


The monad pattern consists of writing two higher-order functions which solve this problem, allowing the programmer to easily nest the application of such functions, by abstracting out the mechanics, and making sure that a function does not choke on an unexpected input type (a wrapped type, when it was expecting a raw type).
# 'Return' or 'unit' which wraps a piece of raw data, returning the wrapped 'monadic' form.
# 'Bind' which applies some other function directly to the contents of a monadic wrapper, obtains a result, and returns a wrapped form of that result.


More specifically, the two higher-order functions of the monad pattern handle the details of: 1. wrapping data in a particular kind of envelope, and 2. Providing other functions with direct access to the contents of an enclosing envelope.


These two functions are sometimes named as follows:
(The term monad derives from [[wp:Monad_(category_theory)|a concept in category theory]]. In ancient Greek the word μοναδικος means 'consisting of units').


# '''Return''' or '''Unit''', which wraps a piece of raw data, returning the wrapped 'monadic' form.
Commonly used monads include the Maybe monad, (in which the wrapper encodes whether or not the raw content is a legal value for a particular type of function), and the List monad, in which raw data is simply contained in a list. When lists are used to represent a range of possible values for a variable name, nesting functions which act on these lists allows a convenient encoding of cartesian products and set comprehensions. In this context, the two higher order monad functions ensure that each data-transforming function (in a nest or composition of such functions) gets the right kind of argument (Raw atomic values versus one or more values 'wrapped in' a list).
# '''Bind''', which applies some other function directly to the contents of a monadic wrapper, obtains a result, and returns a wrapped form of that result.


(Other frequently used monads are the IO monad and the State monad)


(The term monad derives from [[wp:Monad_(category_theory)|a concept in category theory]]. In ancient Greek the word μοναδικος means 'consisting of units').
Demonstrate in your programming language the following:

# Construct a Monad (preferably the Option/Maybe Monad or the List Monad) by writing the 'bind' function and the 'unit' (sometimes known as 'return') function 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>

=={{header|zkl}}==
While I'm unsure of the utility of Monads in a dynamic type-less language, it can be done.
===Maybe Monad===
From the [[wp:Monad_(functional_programming)#The_Maybe_monad|Wikipedia]]

Here we use the Void object as Nothing and define some functions. Sine zkl is type-less, we can consider Maybe as a native type and don't need to define it.
<lang zkl>fcn bind(a,type,b){ if(type.isType(a)) b else Void }
fcn just(x){ if(Deferred.isType(x)) x() else x } // force lazy evaluation
fcn rtn(x) { just(x) }</lang>
Since zkl is eager, add needs to gyrate a bit by creating a lazy result and evaluating that after the binds have done their bizness.
<lang zkl>fcn add(mx,my){
bind(mx,Int,
bind(my,Int,
'+.fp(mx,my))) : rtn(_) // create a lazy mx+my to avoid eager eval
}
add(1,2).println(); // two ints
add(1,2.0).println(); // int and float
add(self,2).println(); // class and int</lang>
{{out}}
<pre>
3
Void
Void
</pre>


Commonly used monads:
===List Monad===
{{trans|Ruby}}
;the Writer monad
Here we create a class to do Monad like things. Unlike Ruby, we can't augment the baked in List/Array object so this more verbose. Also unlike Ruby, we can directly compose as we are applying the composition to each element (vs the list-as-object).
:Nests functions which return their output in an envelope that includes a log string. Nesting ('composing') such functions generates a concatenated log of a chain of function applications.
<lang zkl>class MList{
;the Maybe monad
fcn init(xs){ var list=vm.arglist }
:Nests partial functions which return their output in a wrapper that includes a boolean flag – indicating whether or not the input value was legal. Composition of these functions avoids the need for exception handling when an illegal value is encountered somewhere along the chain of function applications. The '''invalid''' flag is threaded up through the monad, allowing all further attempts at function application to be bypassed.
fcn bind(f) { list=list.apply(f); self }
;the List monad
fcn toString{ list.toString() }
:Nests functions which output ranges of possible values, rather than single values. Composing these functions yields cartesian products, and a convenient encoding of set comprehensions.
}</lang>
<lang zkl>inc:=Op("+",1); // '+(1)
str:="toString";
MList(3,4,5).bind(inc).bind(str).println(" == (4,5,6)");


doub:=Op("*",2);
MList(3,4,5).bind(inc).bind(doub).println(" == (8,10,12)");


(Other frequently used monads include the the IO monad, and the State monad, which make it possible to thread effects and state changes through a 'pure' composition of function applications).
comp:=Utils.Helpers.fcomp; // comp(f,g) == f.g == f(g(x))
MList(3,4,5).bind(comp(doub,inc)).println(" == (8,10,12)");</lang>
{{out}}
<pre>
L("4","5","6") == (4,5,6)
L(8,10,12) == (8,10,12)
L(8,10,12) == (8,10,12)
</pre>

Latest revision as of 13:34, 23 December 2017

In functional programming, the Monad design pattern is a general solution to the problem of nesting (or 'composing') a class of functions which enclose their output values in some kind of useful wrapping. The output envelope might, for example, contain, in addition to the returned value, a log string, or a boolean indicator of whether or not the input was a legal value. Sometimes the output might simply be enclosed in a list representing a range of possible values rather than a single value.

Functions of this type can not be directly nested with each other, because their output type (wrapped) does not match their input type (raw and unwrapped).

The monad pattern consists of writing two higher-order functions which solve this problem, allowing the programmer to easily nest the application of such functions, by abstracting out the mechanics, and making sure that a function does not choke on an unexpected input type (a wrapped type, when it was expecting a raw type).

More specifically, the two higher-order functions of the monad pattern handle the details of: 1. wrapping data in a particular kind of envelope, and 2. Providing other functions with direct access to the contents of an enclosing envelope.

These two functions are sometimes named as follows:

  1. Return or Unit, which wraps a piece of raw data, returning the wrapped 'monadic' form.
  2. Bind, which applies some other function directly to the contents of a monadic wrapper, obtains a result, and returns a wrapped form of that result.


(The term monad derives from a concept in category theory. In ancient Greek the word μοναδικος means 'consisting of units').

Commonly used monads:

the Writer monad
Nests functions which return their output in an envelope that includes a log string. Nesting ('composing') such functions generates a concatenated log of a chain of function applications.
the Maybe monad
Nests partial functions which return their output in a wrapper that includes a boolean flag – indicating whether or not the input value was legal. Composition of these functions avoids the need for exception handling when an illegal value is encountered somewhere along the chain of function applications. The invalid flag is threaded up through the monad, allowing all further attempts at function application to be bypassed.
the List monad
Nests functions which output ranges of possible values, rather than single values. Composing these functions yields cartesian products, and a convenient encoding of set comprehensions.


(Other frequently used monads include the the IO monad, and the State monad, which make it possible to thread effects and state changes through a 'pure' composition of function applications).

Pages in category "Monads"

The following 3 pages are in this category, out of 3 total.