Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Monad (functional programming)
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
=== An example: Maybe === {{Further|Option type}} {{See also|Monad (category theory)#The maybe monad}} One example of a monad is the <code>Maybe</code> type. Undefined null results are one particular pain point that many procedural languages don't provide specific tools for dealing with, requiring use of the [[null object pattern]] or checks to test for invalid values at each operation to handle undefined values. This causes bugs and makes it harder to build robust software that gracefully handles errors. The <code>Maybe</code> type forces the programmer to deal with these potentially undefined results by explicitly defining the two states of a result: <code>Just βresultβ</code>, or <code>Nothing</code>. For example the programmer might be constructing a parser, which is to return an intermediate result, or else signal a condition which the parser has detected, and which the programmer must also handle. With just a little extra functional spice on top, this <code>Maybe</code> type transforms into a fully-featured monad.{{efn|name= gHutton2ndMaybe|Specific motivation for Maybe can be found in (Hutton 2016).<ref name=gHutton2016 >Graham Hutton (2016) ''Programming in Haskell'' 2nd Edition</ref>}}{{rp|12.3 pages 148β151}} In most languages, the Maybe monad is also known as an [[option type]], which is just a type that marks whether or not it contains a value. Typically they are expressed as some kind of [[enumerated type]]. In the [[Rust (programming language)|Rust]] programming language it is called <code>Option<T></code> and variants of this type can either be a value of [[generic type]] <code>T</code>, or the empty variant: <code>None</code>. <syntaxhighlight lang="rust"> // The <T> represents a generic type "T" enum Option<T> { Some(T), None, } </syntaxhighlight> <code>Option<T></code> can also be understood as a "wrapping" type, and this is where its connection to monads comes in. In languages with some form of the Maybe type, there are functions that aid in their use such as composing '''monadic functions''' with each other and testing if a Maybe contains a value. In the following hard-coded example, a Maybe type is used as a result of functions that may fail, in this case the type returns nothing if there is a [[divide-by-zero]].<syntaxhighlight lang="rust"> fn divide(x: Decimal, y: Decimal) -> Option<Decimal> { if y == 0 { return None } else { return Some(x / y) } } // divide(1.0, 4.0) -> returns Some(0.25) // divide(3.0, 0.0) -> returns None </syntaxhighlight>One such way to test whether or not a Maybe contains a value is to use <code>if</code> statements.<syntaxhighlight lang="rust"> let m_x = divide(3.14, 0.0); // see divide function above // The if statement extracts x from m_x if m_x is the Just variant of Maybe if let Some(x) = m_x { println!("answer: ", x) } else { println!("division failed, divide by zero error...") } </syntaxhighlight>Other languages may have [[pattern matching]]<syntaxhighlight lang="rust"> let result = divide(3.0, 2.0); match result { Some(x) => println!("Answer: ", x), None => println!("division failed; we'll get 'em next time."), } </syntaxhighlight>Monads can compose functions that return Maybe, putting them together. A concrete example might have one function take in several Maybe parameters, and return a single Maybe whose value is Nothing when any of the parameters are Nothing, as in the following: <syntaxhighlight lang="rust"> fn chainable_division(maybe_x: Option<Decimal>, maybe_y: Option<Decimal>) -> Option<Decimal> { match (maybe_x, maybe_y) { (Some(x), Some(y)) => { // If both inputs are Some, check for division by zero and divide accordingly if y == 0 { return None } else { return Some(x / y) } }, _ => return None // Otherwise return None } } chainable_division(chainable_division(Some(2.0), Some(0.0)), Some(1.0)); // inside chainable_division fails, outside chainable_division returns None </syntaxhighlight> Instead of repeating <code>Some</code> expressions, we can use something called a ''bind'' operator. (also known as "map", "flatmap", or "shove"<ref name= Beckerman>{{Cite web|last=Beckerman|first=Brian|date=21 November 2012|title=Don't fear the Monad|website=[[YouTube]]|url=https://www.youtube.com/watch?v=ZhuHCtR3xq8&t=2205s}}</ref>{{rp|2205s}}). This operation takes a monad and a function that returns a monad and runs the function on the inner value of the passed monad, returning the monad from the function.<syntaxhighlight lang="rust"> // Rust example using ".map". maybe_x is passed through 2 functions that return Some<Decimal> and Some<String> respectively. // As with normal function composition the inputs and outputs of functions feeding into each other should match wrapped types. (i.e. the add_one function should return a Some<Decimal> which then can be unwrapped to a Decimal for the decimal_to_string function) let maybe_x: Some<Decimal> = Option(1.0) let maybe_result = maybe_x.map(add_one).map(decimal_to_string) </syntaxhighlight>In Haskell, there is an operator ''bind'', or (<code>>>=</code>) that allows for this monadic composition in a more elegant form similar to [[function composition]].{{efn|name= gHutton2ndBind|Hutton abstracts a <code>bind</code> which when given a type ''a'' that may fail, and a mapping ''a''β''b'' that may fail, produces a result ''b'' that may fail. (Hutton, 2016)<ref name=gHutton2016/> }}{{rp|150β151}} <syntaxhighlight lang="haskell"> halve :: Int -> Maybe Int halve x | even x = Just (x `div` 2) | odd x = Nothing -- This code halves x twice. it evaluates to Nothing if x is not a multiple of 4 halve x >>= halve </syntaxhighlight> With <code>>>=</code> available, <code>chainable_division</code> can be expressed much more succinctly with the help of [[anonymous function]]s (i.e. lambdas). Notice in the expression below how the two nested lambdas each operate on the wrapped value in the passed <code>Maybe</code> monad using the bind operator.{{efn|name= gHutton2ndJust|(Hutton 2016) notes that Just might denote Success, and Nothing might denote Failure.<ref name=gHutton2016 />}}{{rp|93}} <syntaxhighlight lang="haskell"> chainable_division(mx,my) = mx >>= ( Ξ»x -> my >>= (Ξ»y -> Just (x / y)) ) </syntaxhighlight> What has been shown so far is basically a monad, but to be more concise, the following is a strict list of qualities necessary for a monad as defined by the following section. ;''Monadic Type'' :A type (<code>Maybe</code>){{efn|name= gHutton2ndMaybe}}{{rp|148β151}} ;''Unit operation'' :A type converter (<code>Just(x)</code>){{efn|name= gHutton2ndJust}}{{rp|93}} ;''Bind operation'' :A combinator for monadic functions ( <code>>>=</code> or <code>.flatMap()</code>){{efn|name= gHutton2ndBind}}{{rp|150β151}} These are the 3 things necessary to form a monad. Other monads may embody different logical processes, and some may have additional properties, but all of them will have these three similar components.<ref name="RealWorldHaskell" /><ref name="Spivey1990">{{cite journal|last1=Spivey|first1=Mike|year=1990|title=A functional theory of exceptions|url=https://www.cs.tufts.edu/comp/150FP/archive/mike-spivey/functional-exns.pdf|journal=Science of Computer Programming|volume=14|issue=1|pages=25β42|doi=10.1016/0167-6423(90)90056-J|doi-access=free}}</ref>
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)