Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

Monad (functional programming)

From Wikipedia, the free encyclopedia
Design pattern in functional programming to build generic types
For the concept in category theory, seeMonad (category theory).

Infunctional programming,monads are a way to structure computations as a sequence of steps, where each step not only produces a value but also some extra information about the computation, such as a potential failure, non-determinism, or side effect. More formally, a monad is atype constructor M equipped with two operations,return:<A>(a:A)->M(A) which lifts a value into the monadic context, andbind:<A,B>(m_a:M(A),f:A->M(B))->M(B) which chains monadic computations. In simpler terms, monads can be thought of asinterfaces implemented on type constructors, that allow for functions to abstract over various type constructor variants that implement monad (e.g.Option,List, etc.).[1][2]

Both the concept of a monad and the term originally come fromcategory theory, where a monad is defined as anendofunctor with additional structure.[a][b] Research beginning in the late 1980s and early 1990s established that monads could bring seemingly disparate computer-science problems under a unified, functional model. Category theory also provides a few formal requirements, known as themonad laws, which should be satisfied by any monad and can be used toverify monadic code.[3][4]

Since monads makesemantics explicit for a kind of computation, they can also be used to implement convenient language features. Some languages, such asHaskell, even offer pre-built definitions in their corelibraries for the general monad structure and common instances.[1][5]

Overview

[edit]

"For a monadm, a value of typem a represents having access to a value of typea within the context of the monad." —C. A. McCann[6]

More exactly, a monad can be used where unrestricted access to a value is inappropriate for reasons specific to the scenario. In the case of the Maybe monad, it is because the value may not exist. In the case of the IO monad, it is because the value may not be known yet, such as when the monad represents user input that will only be provided after a prompt is displayed. In all cases the scenarios in which access makes sense are captured by the bind operation defined for the monad; for the Maybe monad a value is bound only if it exists, and for the IO monad a value is bound only after the previous operations in the sequence have been performed.

A monad can be created by defining atype constructorM and two operations:

  • return :: a -> M a (often also calledunit), which receives a value of typea and wraps it into amonadic value of typeM a, and
  • bind :: (M a) -> (a -> M b) -> (M b) (typically represented as>>=), which receives a monadic value of typeM a and a functionf that accepts values of the base typea. Bind unwrapsM a, appliesf to it, and can process the result off as a monadic valueM b.

(An alternative butequivalent construct using thejoin function instead of thebind operator can be found in the later section§ Derivation from functors.)

With these elements, the programmer composes a sequence of function calls (a "pipeline") with severalbind operators chained together in an expression. Each function call transforms its input plain-type value, and the bind operator handles the returned monadic value, which is fed into the next step in the sequence.

Typically, the bind operator>>= may contain code unique to the monad that performs additional computation steps not available in the function received as a parameter. Between each pair of composed function calls, the bind operator can inject into the monadic valuem a some additional information that is not accessible within the functionf, and pass it along down the pipeline. It can also exert finer control of the flow of execution, for example by calling the function only under some conditions, or executing the function calls in a particular order.

An example: Maybe

[edit]
Further information:Option type
See also:Monad (category theory) § The maybe monad

One example of a monad is theMaybe type. Undefined null results are one particular pain point that many procedural languages don't provide specific tools for dealing with, requiring use of thenull 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. TheMaybe type forces the programmer to deal with these potentially undefined results by explicitly defining the two states of a result:Just ⌑result⌑, orNothing. 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, thisMaybe type transforms into a fully-featured monad.[c]: 12.3 pages 148–151 

In most languages, the Maybe monad is also known as anoption type, which is just a type that marks whether or not it contains a value. Typically they are expressed as some kind ofenumerated type. In theRust programming language it is calledOption<T> and variants of this type can either be a value ofgeneric typeT, or the empty variant:None.

// The <T> represents a generic type "T"enumOption<T>{Some(T),None,}

Option<T> 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 composingmonadic 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 adivide-by-zero.

fndivide(x:Decimal,y:Decimal)->Option<Decimal>{ify==0{returnNone}else{returnSome(x/y)}}// divide(1.0, 4.0) -> returns Some(0.25)// divide(3.0, 0.0) -> returns None

One such way to test whether or not a Maybe contains a value is to useif statements.

letm_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 MaybeifletSome(x)=m_x{println!("answer: ",x)}else{println!("division failed, divide by zero error...")}

Other languages may havepattern matching

letresult=divide(3.0,2.0);matchresult{Some(x)=>println!("Answer: ",x),None=>println!("division failed; we'll get 'em next time."),}

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:

fnchainable_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 accordinglyify==0{returnNone}else{returnSome(x/y)}},_=>returnNone// 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

Instead of repeatingSome expressions, we can use something called abind operator. (also known as "map", "flatmap", or "shove"[8]: 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.

// Rust example using ".map". maybe_x is passed through 2 functions that return Decimal and 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 Decimal which then can be passed to the decimal_to_string function)letmaybe_x:Option<Decimal>=Some(1.0)letmaybe_result=maybe_x.map(add_one).map(decimal_to_string)

In Haskell, there is an operatorbind, or (>>=) that allows for this monadic composition in a more elegant form similar tofunction composition.[d]: 150–151 

halve::Int->MaybeInthalvex|evenx=Just(x`div`2)|oddx=Nothing-- This code halves x twice. it evaluates to Nothing if x is not a multiple of 4halvex>>=halve

With>>= available,chainable_division can be expressed much more succinctly with the help ofanonymous functions (i.e. lambdas). Notice in the expression below how the two nested lambdas each operate on the wrapped value in the passedMaybe monad using the bind operator.[e]: 93 

chainable_division(mx,my)=mx>>=(λx->my>>=(λy->Just(x/y)))

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 (Maybe)[c]: 148–151 
Unit operation
A type converter (Just(x))[e]: 93 
Bind operation
A combinator for monadic functions (>>= or.flatMap())[d]: 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.[1][9]

Definition

[edit]

The more common definition for a monad in functional programming, used in the above example, is actually based on aKleisli triple ⟨T, η, μ⟩ rather than category theory's standard definition. The two constructs turn out to be mathematically equivalent, however, so either definition will yield a valid monad. Given any well-defined basic typesT andU, a monad consists of three parts:

  • Atype constructorM that builds up a monadic typeM T[f]
  • Atype converter, often calledunit orreturn, that embeds an objectx in the monad:
    unit : T → M T[g]
  • Acombinator, typically calledbind (as inbinding a variable) and represented with aninfix operator>>= or a method calledflatMap, that unwraps a monadic variable, then inserts it into a monadic function/expression, resulting in a new monadic value:
    (>>=) : (M T, T → M U) → M U[h] so ifma : M T andf : T → M U, then (ma >>= f) : M U

To fully qualify as a monad though, these three parts must also respect a few laws:

  • unit is aleft-identity forbind:
    unit(x) >>= ff(x)
  • unit is also a right-identity forbind:
    ma >>= unitma
  • bind is essentiallyassociative:[i]
    ma >>= λx → (f(x) >>= g)(ma >>= f) >>= g[1]

Algebraically, this means any monad both gives rise to a category (called theKleisli category)and amonoid in the category of functors (from values to computations), with monadic composition as a binary operator in the monoid[8]: 2450s  andunit as identity in the monoid.

Usage

[edit]

The value of the monad pattern goes beyond merely condensing code and providing a link to mathematical reasoning.Whatever language or defaultprogramming paradigm a developer uses, following the monad pattern brings many of the benefits ofpurely functional programming.Byreifying a specific kind of computation, a monad not onlyencapsulates the tedious details of that computational pattern, but it does so in adeclarative way, improving the code's clarity.As monadic values explicitly represent not only computed values, but computedeffects, a monadic expression can be replaced with its value inreferentially transparent positions, much like pure expressions can be, allowing for many techniques and optimizations based onrewriting.[4]

Typically, programmers will usebind to chain monadic functions into a sequence, which has led some to describe monads as "programmable semicolons", a reference to how manyimperative languages use semicolons to separatestatements.[1][5]However, monads do not actually order computations; even in languages that use them as central features, simpler function composition can arrange steps within a program.A monad's general utility rather lies in simplifying a program's structure and improvingseparation of concerns through abstraction.[4][11]

The monad structure can also be seen as a uniquely mathematical andcompile time variation on thedecorator pattern.Some monads can pass along extra data that is inaccessible to functions, and some even exert finer control over execution, for example only calling a function under certain conditions.Because they let application programmers implementdomain logic while offloading boilerplate code onto pre-developed modules, monads can even be considered a tool foraspect-oriented programming.[12]

One other noteworthy use for monads is isolating side-effects, likeinput/output or mutablestate, in otherwise purely functional code.Even purely functional languagescan still implement these "impure" computations without monads, via an intricate mix of function composition andcontinuation-passing style (CPS) in particular.[2]With monads though, much of this scaffolding can be abstracted away, essentially by taking each recurring pattern in CPS code and bundling it into a distinct monad.[4]

If a language does not support monads by default, it is still possible to implement the pattern, often without much difficulty.When translated from category-theory to programming terms, the monad structure is ageneric concept and can be defined directly in any language that supports an equivalent feature forbounded polymorphism.A concept's ability to remain agnostic about operational details while working on underlying types is powerful, but the unique features and stringent behavior of monads set them apart from other concepts.[13]

Applications

[edit]

Discussions of specific monads will typically focus on solving a narrow implementation problem since a given monad represents a specific computational form.In some situations though, an application can even meet its high-level goals by using appropriate monads within its core logic.

Here are just a few applications that have monads at the heart of their designs:

History

[edit]

The term "monad" in programming dates to theAPL andJ programming languages, which do tend toward being purely functional. However, in those languages, "monad" is only shorthand for a function taking one parameter (a function with two parameters being a "dyad", and so on).[19]

The mathematicianRoger Godement was the first to formulate the concept of a monad (dubbing it a "standard construction") in the late 1950s, though the term "monad" that came to dominate was popularized by category-theoristSaunders Mac Lane.[citation needed] The form defined above usingbind, however, was originally described in 1965 by mathematicianHeinrich Kleisli in order to prove that any monad could be characterized as anadjunction between two (covariant) functors.[20]

Starting in the 1980s, a vague notion of the monad pattern began to surface in the computer science community.According to programming language researcherPhilip Wadler, computer scientistJohn C. Reynolds anticipated several facets of it in the 1970s and early 1980s, when he discussed the value ofcontinuation-passing style, of category theory as a rich source for formal semantics, and of the type distinction between values and computations.[4]The research languageOpal, which was actively designed up until 1990, also effectively based I/O on a monadic type, but the connection was not realized at the time.[21]

The computer scientistEugenio Moggi was the first to explicitly link the monad of category theory to functional programming, in a conference paper in 1989,[22] followed by a more refined journal submission in 1991. In earlier work, several computer scientists had advanced using category theory to provide semantics for thelambda calculus. Moggi's key insight was that a real-world program is not just a function from values to other values, but rather a transformation that formscomputations on those values. When formalized in category-theoretic terms, this leads to the conclusion that monads are the structure to represent these computations.[3]

Several others popularized and built on this idea, including Philip Wadler andSimon Peyton Jones, both of whom were involved in the specification of Haskell. In particular, Haskell used a problematic "lazy stream" model up through v1.2 to reconcile I/O withlazy evaluation, until switching over to a more flexible monadic interface.[23] The Haskell community would go on to apply monads to many problems in functional programming, and in the 2010s, researchers working with Haskell eventually recognized that monads areapplicative functors;[24][j] and that both monads andarrows aremonoids.[26]

At first, programming with monads was largely confined to Haskell and its derivatives, but as functional programming has influenced other paradigms, many languages have incorporated a monad pattern (in spirit if not in name). Formulations now exist inScheme,Perl,Python,Racket,Clojure,Scala,F#, and have also been considered for a newML standard.[citation needed]

Analysis

[edit]

One benefit of the monad pattern is bringing mathematical precision on the composition of computations.Not only can the monad laws be used to check an instance's validity, but features from related structures (like functors) can be used throughsubtyping.

Verifying the monad laws

[edit]

Returning to theMaybe example, its components were declared to make up a monad, but no proof was given that it satisfies the monad laws.

This can be rectified by plugging the specifics ofMaybe into one side of the general laws, then algebraically building a chain of equalities to reach the other side:

Law 1:  eta(a) >>= f(x)  ⇔  (Just a) >>= f(x)  ⇔  f(a)
Law 2:  ma >>= eta(x)           ⇔  maif mais (Just a)then            eta(a)              ⇔ Just aelseor            Nothing             ⇔ Nothingend if
Law 3:(ma >>= f(x)) >>= g(y)                       ⇔  ma >>=(f(x) >>= g(y))if (ma >>= f(x))is (Just b)thenif mais (Just a)then            g(ma >>= f(x))                                (f(x) >>= g(y)) aelseelse            Nothing                                         Nothingend ifend ifif mais (Just a)and f(a)is (Just b)then                             (g ∘ f) aelse if mais (Just a)and f(a)is Nothing then                       Nothingelse                       Nothingend if

Derivation from functors

[edit]

Though rarer in computer science, one can use category theory directly, which defines a monad as afunctor with two additionalnatural transformations.[k]So to begin, a structure requires ahigher-order function (or "functional") namedmap to qualify as a functor:

map : (a → b) → (ma → mb)

This is not always a major issue, however, especially when a monad is derived from a pre-existing functor, whereupon the monad inheritsmap automatically. (For historical reasons, thismap is instead calledfmap in Haskell.)

A monad's first transformation is actually the sameunit from the Kleisli triple, but following the hierarchy of structures closely, it turns outunit characterizes anapplicative functor, an intermediate structure between a monad and a basic functor. In the applicative context,unit is sometimes referred to aspure but is still the same function. What does differ in this construction is the lawunit must satisfy; asbind is not defined, the constraint is given in terms ofmap instead:

(unit ∘ φ) x ↔ ((map φ) ∘ unit) x ↔ x[27]

The final leap from applicative functor to monad comes with the second transformation, thejoin function (in category theory this is a natural transformation usually calledμ), which "flattens" nested applications of the monad:

join(mma) : M (M T) → M T

As the characteristic function,join must also satisfy three variations on the monad laws:

(join ∘ (map join)) mmma ↔ (join ∘ join) mmma ↔ ma
(join ∘ (map unit)) ma ↔ (join ∘ unit) ma ↔ ma
(join ∘ (map map φ)) mma ↔ ((map φ) ∘ join) mma ↔ mb

Regardless of whether a developer defines a direct monad or a Kleisli triple, the underlying structure will be the same, and the forms can be derived from each other easily:

(map φ) ma ↔ ma >>= (unit ∘ φ)
join(mma) ↔ mma >>= id
ma >>= f ↔ (join ∘ (map f)) ma[28]

Another example: List

[edit]
See also:Monad (category theory) § The list and set monads

TheList monad naturally demonstrates how deriving a monad from a simpler functor can come in handy.In many languages, a list structure comes pre-defined along with some basic features, so aList type constructor andappend operator (represented with++ for infix notation) are assumed as already given here.

Embedding a plain value in a list is also trivial in most languages:

unit(x)  =  [x]

From here, applying a function iteratively with alist comprehension may seem like an easy choice forbind and converting lists to a full monad.The difficulty with this approach is thatbind expects monadic functions, which in this case will output lists themselves;as more functions are applied, layers of nested lists will accumulate, requiring more than a basic comprehension.

However, a procedure to apply anysimple function over the whole list, in other wordsmap, is straightforward:

(map φ) xlist  =  [ φ(x1), φ(x2), ..., φ(xn) ]

Now, these two procedures already promoteList to an applicative functor.To fully qualify as a monad, only a correct notion ofjoin to flatten repeated structure is needed, but for lists, that just means unwrapping an outer list to append the inner ones that contain values:

join(xlistlist)  =  join([xlist1, xlist2, ..., xlistn])                 =  xlist1 ++ xlist2 ++ ... ++ xlistn

The resulting monad is not only a list, but one that automatically resizes and condenses itself as functions are applied.bind can now also be derived with just a formula, then used to feedList values through a pipeline of monadic functions:

TheList monad can greatly simplify the use of multivalued functions, such as complex roots.[29]
(xlist >>= f)  =  join ∘ (map f) xlist

One application for this monadic list is representingnondeterministic computation.List can hold results for all execution paths in an algorithm, then condense itself at each step to "forget" which paths led to which results (a sometimes important distinction from deterministic, exhaustive algorithms).[citation needed]Another benefit is that checks can be embedded in the monad; specific paths can be pruned transparently at their first point of failure, with no need to rewrite functions in the pipeline.[28]

A second situation whereList shines is composingmultivalued functions.For instance, thenthcomplex root of a number should yieldn distinct complex numbers, but if anothermth root is then taken of those results, the finalm•n values should be identical to the output of them•nth root.List completely automates this issue away, condensing the results from each step into a flat, mathematically correct list.[29]

Techniques

[edit]

Monads present opportunities for interesting techniques beyond just organizing program logic. Monads can lay the groundwork for useful syntactic features while their high-level and mathematical nature enable significant abstraction.

Syntactic sugardo-notation

[edit]

Although usingbind openly often makes sense, many programmers prefer a syntax that mimics imperative statements(calleddo-notation in Haskell,perform-notation inOCaml,computation expressions inF#,[30] andfor comprehension inScala). This is onlysyntactic sugar that disguises a monadic pipeline as acode block; the compiler will then quietly translate these expressions into underlying functional code.

Translating theadd function from theMaybe into Haskell can show this feature in action. A non-monadic version ofadd in Haskell looks like this:

addmxmy=casemxofNothing->NothingJustx->casemyofNothing->NothingJusty->Just(x+y)

In monadic Haskell,return is the standard name forunit, plus lambda expressions must be handled explicitly, but even with these technicalities, theMaybe monad makes for a cleaner definition:

addmxmy=mx>>=(\x->my>>=(\y->return(x+y)))

With do-notation though, this can be distilled even further into a very intuitive sequence:

addmxmy=dox<-mxy<-myreturn(x+y)

A second example shows howMaybe can be used in an entirely different language: F#.With computation expressions, a "safe division" function that returnsNone for an undefined operandor division by zero can be written as:

letreadNum()=lets=Console.ReadLine()letsucc,v=Int32.TryParse(s)if(succ)thenSome(v)elseNoneletsecure_div=maybe{let!x=readNum()let!y=readNum()if(y=0)thenNoneelsereturn(x/y)}

At build-time, the compiler will internally "de-sugar" this function into a denser chain ofbind calls:

maybe.Delay(fun()->maybe.Bind(readNum(),funx->maybe.Bind(readNum(),funy->if(y=0)thenNoneelsemaybe.Return(x/y))))

For a last example, even the general monad laws themselves can be expressed in do-notation:

do{x<-returnv;fx}==do{fv}do{x<-m;returnx}==do{m}do{y<-do{x<-m;fx};gy}==do{x<-m;y<-fx;gy}

General interface

[edit]

Every monad needs a specific implementation that meets the monad laws, but other aspects like the relation to other structures or standard idioms within a language are shared by all monads.As a result, a language or library may provide a generalMonad interface withfunction prototypes, subtyping relationships, and other general facts.Besides providing a head-start to development and guaranteeing a new monad inherits features from a supertype (such as functors), checking a monad's design against the interface adds another layer of quality control.[citation needed]

Operators

[edit]

Monadic code can often be simplified even further through the judicious use of operators.Themap functional can be especially helpful since it works on more than just ad-hoc monadic functions; so long as a monadic function should work analogously to a predefined operator,map can be used to instantly "lift" the simpler operator into a monadic one.[l]With this technique, the definition ofadd from theMaybe example could be distilled into:

add(mx,my)  =  map (+)

The process could be taken even one step further by definingadd not just forMaybe, but for the wholeMonad interface.By doing this, any new monad that matches the structure interface and implements its ownmap will immediately inherit a lifted version ofadd too.The only change to the function needed is generalizing the type signature:

add : (Monad Number, Monad Number)  →  Monad Number[31]

Another monadic operator that is also useful for analysis is monadic composition (represented as infix>=> here), which allows chaining monadic functions in a more mathematical style:

(f >=> g)(x)  =  f(x) >>= g

With this operator, the monad laws can be written in terms of functions alone, highlighting the correspondence to associativity and existence of an identity:

(unit >=> g)     ↔  g(f >=> unit)     ↔  f(f >=> g) >=> h  ↔  f >=> (g >=> h)[1]

In turn, the above shows the meaning of the "do" block in Haskell:

do _p <- f(x) _q <- g(_p) h(_q)          ↔ ( f >=> g >=> h )(x)

More examples

[edit]

Identity monad

[edit]

The simplest monad is theIdentity monad, which just annotates plain values and functions to satisfy the monad laws:

newtype Id T  =  Tunit(x)    =  x(x >>= f)  =  f(x)

Identity does actually have valid uses though, such as providing abase case for recursivemonad transformers.It can also be used to perform basic variable assignment within an imperative-style block.[m][citation needed]

Collections

[edit]

Any collection with a properappend is already a monoid, but it turns out thatList is not the onlycollection that also has a well-definedjoin and qualifies as a monad.One can even mutateList into these other monadic collections by simply imposing special properties onappend:[n][o]

CollectionMonoid propertiesCombinatoric properties
Commutative?Idempotent?DetailsOrdered?Unique items?
ListNoNoFree monoidYesNo
FinitemultisetYesNoNoNo
FinitesetYesYesNoYes

IO monad (Haskell)

[edit]

As already mentioned, pure code should not have unmanaged side effects, but that does not preclude a program fromexplicitly describing and managing effects.This idea is central to Haskell'sIO monad, where an object of typeIO a can be seen as describing an action to be performed in the world, optionally providing information about the world of typea. An action that provides no information about the world has the typeIO (), "providing" the dummy value().When a programmer binds anIO value to a function, the function computes the next action to be performed based on the information about the world provided by the previous action (input from users, files, etc.).[23] Most significantly, because the value of the IO monad can only be bound to a function that computes another IO monad, the bind function imposes a discipline of a sequence of actions where the result of an action can only be provided to a function that will compute the next action to perform. This means that actions which do not need to be performed never are, and actions that do need to be performed have a well defined sequence.

For example, Haskell has several functions for acting on the widerfile system, including one that checks whether a file exists and another that deletes a file.Their two type signatures are:

doesFileExist::FilePath->IOBoolremoveFile::FilePath->IO()

The first is interested in whether a given file really exists, and as a result, outputs aBoolean value within theIO monad.The second function, on the other hand, is only concerned with acting on the file system so theIO container it outputs is empty.

IO is not limited just to file I/O though; it even allows for user I/O, and along with imperative syntax sugar, can mimic a typical"Hello, World!" program:

main::IO()main=doputStrLn"Hello, world!"putStrLn"What is your name, user?"name<-getLineputStrLn("Nice to meet you, "++name++"!")

Desugared, this translates into the following monadic pipeline (>> in Haskell is just a variant ofbind for when only monadic effects matter and the underlying result can be discarded):

main::IO()main=putStrLn"Hello, world!">>putStrLn"What is your name, user?">>getLine>>=(\name->putStrLn("Nice to meet you, "++name++"!"))

Writer monad (JavaScript)

[edit]

Another common situation is keeping alog file or otherwise reporting a program's progress.Sometimes, a programmer may want to log even more specific, technical data for laterprofiling ordebugging.TheWriter monad can handle these tasks by generating auxiliary output that accumulates step-by-step.

To show how the monad pattern is not restricted to primarily functional languages, this example implements aWriter monad inJavaScript.First, an array (with nested tails) allows constructing theWriter type as alinked list.The underlying output value will live in position 0 of the array, and position 1 will implicitly hold a chain of auxiliary notes:

constwriter=value=>[value,[]];

Definingunit is also very simple:

constunit=value=>[value,[]];

Onlyunit is needed to define simple functions that outputWriter objects with debugging notes:

constsquared=x=>[x*x,[`${x} was squared.`]];consthalved=x=>[x/2,[`${x} was halved.`]];

A true monad still requiresbind, but forWriter, this amounts simply to concatenating a function's output to the monad's linked list:

constbind=(writer,transform)=>{const[value,log]=writer;const[result,updates]=transform(value);return[result,log.concat(updates)];};

The sample functions can now be chained together usingbind, but defining a version of monadic composition (calledpipelog here) allows applying these functions even more succinctly:

constpipelog=(writer,...transforms)=>transforms.reduce(bind,writer);

The final result is a clean separation of concerns between stepping through computations and logging them to audit later:

pipelog(unit(4),squared,halved);// Resulting writer object = [8, ['4 was squared.', '16 was halved.']]

Environment monad

[edit]
See also:Monad (category theory) § The environment monad

An environment monad (also called areader monad and afunction monad) allows a computation to depend on values from a shared environment. The monad type constructor maps a typeT to functions of typeET, whereE is the type of the shared environment. The monad functions are:return:TET=tetbind:(ET)(TET)ET=rfef(re)e{\displaystyle {\begin{array}{ll}{\text{return}}\colon &T\rightarrow E\rightarrow T=t\mapsto e\mapsto t\\{\text{bind}}\colon &(E\rightarrow T)\rightarrow (T\rightarrow E\rightarrow T')\rightarrow E\rightarrow T'=r\mapsto f\mapsto e\mapsto f\,(r\,e)\,e\end{array}}}

The following monadic operations are useful:ask:EE=idElocal:(EE)(ET)ET=fcec(fe){\displaystyle {\begin{array}{ll}{\text{ask}}\colon &E\rightarrow E={\text{id}}_{E}\\{\text{local}}\colon &(E\rightarrow E)\rightarrow (E\rightarrow T)\rightarrow E\rightarrow T=f\mapsto c\mapsto e\mapsto c\,(f\,e)\end{array}}}

Theask operation is used to retrieve the current context, whilelocal executes a computation in a modified subcontext. As in a state monad, computations in the environment monad may be invoked by simply providing an environment value and applying it to an instance of the monad.

Formally, a value in an environment monad is equivalent to a function with an additional, anonymous argument;return andbind are equivalent to theK andS combinators, respectively, in theSKI combinator calculus.

State monads

[edit]
See also:Monad (category theory) § The state monad

A state monad allows a programmer to attach state information of any type to a calculation. Given any value type, the corresponding type in the state monad is a function which accepts a state, then outputs a new state (of types) along with a return value (of typet). This is similar to an environment monad, except that it also returns a new state, and thus allows modeling amutable environment.

typeStatest=s->(t,s)

Note that this monad takes a type parameter, the type of the state information. The monad operations are defined as follows:

-- "return" produces the given value without changing the state.returnx=\s->(x,s)-- "bind" modifies m so that it applies f to its result.m>>=f=\r->let(x,s)=mrin(fx)s

Useful state operations include:

get=\s->(s,s)-- Examine the state at this point in the computation.puts=\_->((),s)-- Replace the state.modifyf=\s->((),fs)-- Update the state

Another operation applies a state monad to a given initial state:

runState::Statesa->s->(a,s)runStatets=ts

do-blocks in a state monad are sequences of operations that can examine and update the state data.

Informally, a state monad of state typeS maps the type of return valuesT into functions of typeST×S{\displaystyle S\rightarrow T\times S}, whereS is the underlying state. Thereturn andbind function are:

return:TST×S=ts(t,s)bind:(ST×S)(TST×S)ST×S =mks(k t s)where(t,s)=ms{\displaystyle {\begin{array}{ll}{\text{return}}\colon &T\rightarrow S\rightarrow T\times S=t\mapsto s\mapsto (t,s)\\{\text{bind}}\colon &(S\rightarrow T\times S)\rightarrow (T\rightarrow S\rightarrow T'\times S)\rightarrow S\rightarrow T'\times S\ =m\mapsto k\mapsto s\mapsto (k\ t\ s')\quad {\text{where}}\;(t,s')=m\,s\end{array}}}.

From the category theory point of view, a state monad is derived from the adjunction between the product functor and the exponential functor, which exists in anycartesian closed category by definition.

Continuation monad

[edit]

Acontinuation monad[p] with return typeR maps typeT into functions of type(TR)R{\displaystyle \left(T\rightarrow R\right)\rightarrow R}. It is used to modelcontinuation-passing style. The return and bind functions are as follows:

return:T(TR)R=tfftbind:((TR)R)(T(TR)R)(TR)R=cfkc(tftk){\displaystyle {\begin{array}{ll}{\text{return}}\colon &T\rightarrow \left(T\rightarrow R\right)\rightarrow R=t\mapsto f\mapsto f\,t\\{\text{bind}}\colon &\left(\left(T\rightarrow R\right)\rightarrow R\right)\rightarrow \left(T\rightarrow \left(T'\rightarrow R\right)\rightarrow R\right)\rightarrow \left(T'\rightarrow R\right)\rightarrow R=c\mapsto f\mapsto k\mapsto c\,\left(t\mapsto f\,t\,k\right)\end{array}}}

Thecall-with-current-continuation function is defined as follows:

call/cc: ((T(TR)R)(TR)R)(TR)R=fk(f(txkt)k){\displaystyle {\text{call/cc}}\colon \ \left(\left(T\rightarrow \left(T'\rightarrow R\right)\rightarrow R\right)\rightarrow \left(T\rightarrow R\right)\rightarrow R\right)\rightarrow \left(T\rightarrow R\right)\rightarrow R=f\mapsto k\mapsto \left(f\left(t\mapsto x\mapsto k\,t\right)\,k\right)}

Program logging

[edit]

The following code is pseudocode.Suppose we have two functionsfoo andbar, with types

foo:int->intbar:int->int

That is, both functions take in an integer and return another integer. Then we can apply the functions in succession like so:

foo(barx)

Where the result is the result offoo applied to the result ofbar applied tox.

But suppose we are debugging our program, and we would like to add logging messages tofoo andbar.So we change the types as so:

foo:int->int*stringbar:int->int*string

So that both functions return a tuple, with the result of the application as the integer, and a logging message with information about the applied function and all the previously applied functions as the string.

Unfortunately, this means we can no longercomposefoo andbar, as their input typeint is not compatible with their output typeint * string. And although we can again gain composability by modifying the types of each function to beint * string -> int * string, this would require us to add boilerplate code to each function to extract the integer from the tuple, which would get tedious as the number of such functions increases.

Instead, let us define a helper function to abstract away this boilerplate for us:

bind:int*string->(int->int*string)->int*string

bind takes in an integer and string tuple, then takes in a function (likefoo) that maps from an integer to an integer and string tuple. Its output is an integer and string tuple, which is the result of applying the input function to the integer within the input integer and string tuple. In this way, we only need to write boilerplate code to extract the integer from the tuple once, inbind.

Now we have regained some composability. For example:

bind(bind(x,s)bar)foo

Where(x,s) is an integer and string tuple.[q]

To make the benefits even clearer, let us define an infix operator as an alias forbind:

(>>=):int*string->(int->int*string)->int*string

So thatt >>= f is the same asbind t f.

Then the above example becomes:

((x,s)>>=bar)>>=foo

Finally, we define a new function to avoid writing(x, "") every time we wish to create an empty logging message, where"" is the empty string.

return:int->int*string

Which wrapsx in the tuple described above.

The result is a pipeline for logging messages:

((returnx)>>=bar)>>=foo

That allows us to more easily log the effects ofbar andfoo onx.

int * string denotes a pseudo-codedmonadic value.[q]bind andreturn are analogous to the corresponding functions of the same name.In fact,int * string,bind, andreturn form a monad.

Additive monads

[edit]

Anadditive monad is a monad endowed with an additional closed, associative, binary operatormplus and anidentity element undermplus, calledmzero.TheMaybe monad can be considered additive, withNothing asmzero and a variation on theOR operator asmplus.List is also an additive monad, with the empty list[] acting asmzero and the concatenation operator++ asmplus.

Intuitively,mzero represents a monadic wrapper with no value from an underlying type, but is also considered a "zero" (rather than a "one") since it acts as anabsorber forbind, returningmzero whenever bound to a monadic function.This property is two-sided, andbind will also returnmzero when any value is bound to a monadiczero function.

In category-theoretic terms, an additive monad qualifies once as a monoid over monadic functions withbind (as all monads do), and again over monadic values viamplus.[32][r]

Free monads

[edit]

Sometimes, the general outline of a monad may be useful, but no simple pattern recommends one monad or another.This is where afree monad comes in; as afree object in the category of monads, it can represent monadic structure without any specific constraints beyond the monad laws themselves.Just as afree monoid concatenates elements without evaluation, a free monad allows chaining computations with markers to satisfy the type system, but otherwise imposes no deeper semantics itself.

For example, by working entirely through theJust andNothing markers, theMaybe monad is in fact a free monad.TheList monad, on the other hand, is not a free monad since it brings extra, specific facts about lists (likeappend) into its definition.One last example is an abstract free monad:

dataFreefa=Purea|Free(f(Freefa))unit::a->Freefaunitx=Purexbind::Functorf=>Freefa->(a->Freefb)->Freefbbind(Purex)f=fxbind(Freex)f=Free(fmap(\y->bindyf)x)

Free monads, however, arenot restricted to a linked-list like in this example, and can be built around other structures liketrees.

Using free monads intentionally may seem impractical at first, but their formal nature is particularly well-suited for syntactic problems.A free monad can be used to track syntax and type while leaving semantics for later, and has found use in parsers andinterpreters as a result.[33]Others have applied them to more dynamic, operational problems too, such as providingiteratees within a language.[34]

Comonads

[edit]

Besides generating monads with extra properties, for any given monad, one can also define acomonad.Conceptually, if monads represent computations built up from underlying values, then comonads can be seen as reductions back down to values.Monadic code, in a sense, cannot be fully "unpacked"; once a value is wrapped within a monad, it remains quarantined there along with any side-effects (a good thing in purely functional programming).Sometimes though, a problem is more about consuming contextual data, which comonads can model explicitly.

Technically, a comonad is thecategorical dual of a monad, which loosely means that it will have the same required components, only with the direction of the type signaturesreversed.Starting from thebind-centric monad definition, a comonad consists of:

  • A type constructorW that marks the higher-order typeW T
  • The dual ofunit, calledcounit here, extracts the underlying value from the comonad:
counit(wa) : W T → T
  • A reversal ofbind (also represented with=>>) thatextends a chain of reducing functions:
(wa =>> f) : (W U, W U → T) → W T[s]

extend andcounit must also satisfy duals of the monad laws:

counit ∘( (wa =>> f) → wb)  ↔  f(wa) → bwa =>> counit  ↔  wawa( (=>> f(wx = wa)) → wb (=>> g(wy = wb)) → wc)( wa (=>> f(wx = wa)) → wb) (=>> g(wy = wb)) → wc

Analogous to monads, comonads can also be derived from functors using a dual ofjoin:

  • duplicate takes an already comonadic value and wraps it in another layer of comonadic structure:
duplicate(wa) : W T → W (W T)

While operations likeextend are reversed, however, a comonad doesnot reverse functions it acts on, and consequently, comonads are still functors withmap, notcofunctors.The alternate definition withduplicate,counit, andmap must also respect its own comonad laws:

((map duplicate) ∘ duplicate) wa  ↔  (duplicate ∘ duplicate) wa  ↔  wwwa((map counit) ∘ duplicate)    wa  ↔  (counit ∘ duplicate)    wa  ↔  wa((map map φ) ∘ duplicate)     wa  ↔  (duplicate ∘ (map φ))   wa  ↔  wwb

And as with monads, the two forms can be converted automatically:

(map φ) wa    ↔  wa =>> (φ ∘ counit) wxduplicate wa  ↔  wa =>> wx
wa =>> f(wx)  ↔  ((map f) ∘ duplicate) wa

A simple example is theProduct comonad, which outputs values based on an input value and shared environment data.In fact, theProduct comonad is just the dual of theWriter monad and effectively the same as theReader monad (both discussed below).Product andReader differ only in which function signatures they accept, and how they complement those functions by wrapping or unwrapping values.

A less trivial example is theStream comonad, which can be used to representdata streams and attach filters to the incoming signals withextend.In fact, while not as popular as monads, researchers have found comonads particularly useful forstream processing and modelingdataflow programming.[35][36]

Due to their strict definitions, however, one cannot simply move objects back and forth between monads and comonads.As an even higher abstraction,arrows can subsume both structures, but finding more granular ways to combine monadic and comonadic code is an active area of research.[37][38]

See also

[edit]

Alternatives for modeling computations:

  • Effect systems (particularly algebraic effect handlers) are a different way to describe side effects as types
  • Uniqueness types are a third approach to handling side-effects in functional languages

Related design concepts:

  • Aspect-oriented programming emphasizes separating out ancillary bookkeeping code to improve modularity and simplicity
  • Inversion of control is the abstract principle of calling specific functions from an overarching framework
  • Type classes are a specific language feature used to implement monads and other structures in Haskell
  • Thedecorator pattern is a more concrete, ad-hoc way to achieve similar benefits in object-oriented programming

Generalizations of monads:

  • Applicative functors generalize from monads by keeping onlyunit and laws relating it tomap
  • Arrows use additional structure to bring plain functions and monads under a single interface
  • Monad transformers act on distinct monads to combine them modularly

Notes

[edit]
  1. ^More formally, a monad is amonoid in the category ofendofunctors.
  2. ^Due to the fact that functions on multiplefree variables are common in programming, monads as described in this article are technically what category theorists would callstrong monads.[3]
  3. ^abSpecific motivation for Maybe can be found in (Hutton 2016).[7]
  4. ^abHutton abstracts abind which when given a typea that may fail, and a mappingab that may fail, produces a resultb that may fail. (Hutton, 2016)[7]
  5. ^ab(Hutton 2016) notes that Just might denote Success, and Nothing might denote Failure.[7]
  6. ^Semantically,M is not trivial and represents anendofunctor over thecategory of all well-typed values:M:ValVal{\displaystyle M:{\mathit {Val}}\to {\mathit {Val}}}
  7. ^While a (parametrically polymorphic) function in programming terms,unit (often calledη in category theory) is mathematically anatural transformation, which maps betweenfunctors:ηA:id(ValA)M(ValA){\displaystyle \eta _{A}:\mathrm {id} ({\mathit {Val}}_{A})\to M({\mathit {Val}}_{A})}
  8. ^bind, on the other hand, is not a natural transformation in category theory, but rather an extension{\displaystyle -^{*}} thatlifts a mapping (from values to computations) into a morphism between computations:f:ValAM(ValB),f:M(ValA)M(ValB){\displaystyle \forall f:{\mathit {Val}}_{A}\to M({\mathit {Val}}_{B}),f^{*}:M({\mathit {Val}}_{A})\to M({\mathit {Val}}_{B})}
  9. ^Strictly speaking,bind may not be formally associative in all contexts because it corresponds to application withinlambda calculus, not mathematics. In rigorous lambda-calculus, evaluating abind may require first wrapping the right term (when binding two monadic values) or the bind itself (between two monadic functions) in ananonymous function to still accept input from the left.[10]
  10. ^By GHC version 7.10.1, and going forward, Haskell began enforcing Haskell's 2014 Applicative Monad proposal (AMP) which requires the insertion of 7 lines of code into any existing modules which use monads.[25]
  11. ^These natural transformations are usually denoted as morphisms η, μ. That is: η, μ denoteunit, andjoin respectively.
  12. ^Some languages like Haskell even provide a pseudonym formap in other contexts calledlift, along with multiple versions for different parameter counts, a detail ignored here.
  13. ^In category theory, theIdentity monad can also be viewed as emerging fromadjunction of any functor with its inverse.
  14. ^Category theory views these collection monads as adjunctions between thefree functor and different functors from thecategory of sets to thecategory of monoids.
  15. ^Here the task for the programmer is to construct an appropriate monoid, or perhaps to choose a monoid from a library.
  16. ^The reader may wish to follow McCann's thread[6] and compare it with the Types below.
  17. ^abIn this case, thebind haspasted in astring where previously only aninteger had been; that is, the programmer has constructed anadjunction: a tuple(x,s), denotedint * string in the pseudocode§ above.
  18. ^Algebraically, the relationship between the two (non-commutative) monoid aspects resembles that of anear-semiring, and some additive monads do qualify as such. However, not all additive monads meet thedistributive laws of even a near-semiring.[32]
  19. ^In Haskell,extend is actually defined with the inputs swapped, but as currying is not used in this article, it is defined here as the exact dual ofbind.

References

[edit]
  1. ^abcdefO'Sullivan, Bryan; Goerzen, John; Stewart, Don (2009)."Monads".Real World Haskell. Sebastopol, California: O'Reilly Media. chapter 14.ISBN 978-0596514983.
  2. ^abWadler, Philip (June 1990).Comprehending Monads. ACM Conference on LISP and Functional Programming. Nice, France.CiteSeerX 10.1.1.33.5381.
  3. ^abcMoggi, Eugenio (1991)."Notions of computation and monads"(PDF).Information and Computation.93 (1):55–92.CiteSeerX 10.1.1.158.5275.doi:10.1016/0890-5401(91)90052-4.
  4. ^abcdeWadler, Philip (January 1992).The essence of functional programming. 19th Annual ACM Symposium on Principles of Programming Languages. Albuquerque, New Mexico.CiteSeerX 10.1.1.38.9516.
  5. ^abHudak, Paul; Peterson, John; Fasel, Joseph (1999)."About Monads".A Gentle Introduction to Haskell 98. chapter 9.
  6. ^abC. A. McCann's answer (Jul 23 '10 at 23:39) How and why does the Haskell Cont monad work?
  7. ^abcGraham Hutton (2016)Programming in Haskell 2nd Edition
  8. ^abBeckman, Brian (21 November 2012)."Don't fear the Monad".YouTube.
  9. ^Spivey, Mike (1990)."A functional theory of exceptions"(PDF).Science of Computer Programming.14 (1):25–42.doi:10.1016/0167-6423(90)90056-J.
  10. ^"Monad laws".HaskellWiki. haskell.org. Retrieved14 October 2018.
  11. ^"What a Monad is not". 7 October 2018.
  12. ^De Meuter, Wolfgang (1997).Monads as a theoretical foundation for AOP(PDF). International Workshop on Aspect Oriented Programming at ECOOP. Jyväskylä, Finland.CiteSeerX 10.1.1.25.8262.
  13. ^"Monad (sans metaphors)".HaskellWiki. 1 November 2009. Retrieved24 October 2018.
  14. ^O'Sullivan, Bryan; Goerzen, John; Stewart, Don (2009)."Using Parsec".Real World Haskell. Sebastopol, California: O'Reilly Media. chapter 16.ISBN 978-0596514983.
  15. ^Stewart, Don (17 May 2007)."Roll Your Own Window Manager: Tracking Focus with a Zipper".Control.Monad.Writer.Archived from the original on 20 February 2018. Retrieved19 November 2018.
  16. ^Benton, Nick (2015)."Categorical Monads and Computer Programming"(PDF).London Mathematical Society Impact150 Stories.1. Retrieved19 November 2018.
  17. ^Kiselyov, Olag (2007). "Delimited Continuations in Operating Systems".Modeling and Using Context. Lecture Notes in Computer Science. Vol. 4635. Springer Berlin Heidelberg. pages 291--302.doi:10.1007/978-3-540-74255-5_22.ISBN 978-3-540-74255-5.
  18. ^Meijer, Erik (27 March 2012)."Your Mouse is a Database".ACM Queue.10 (3):20–33.doi:10.1145/2168796.2169076.
  19. ^Iverson, Kenneth (September 1987)."A dictionary of APL".APL Quote Quad.18 (1):5–40.doi:10.1145/36983.36984.ISSN 1088-6826.S2CID 18301178. Retrieved19 November 2018.
  20. ^Kleisli, Heinrich (1965)."Every standard construction is induced by a pair of adjoint functors"(PDF).Proceedings of the American Mathematical Society.16 (3):544–546.doi:10.1090/S0002-9939-1965-0177024-4. Retrieved19 November 2018.
  21. ^Peter Pepper, ed. (November 1997).The Programming Language Opal (Technical report) (5th corrected ed.). Fachbereich Informatik, Technische Universität Berlin.CiteSeerX 10.1.1.40.2748.
  22. ^Moggi, Eugenio (June 1989).Computational lambda-calculus and monads(PDF). Fourth Annual Symposium on Logic in computer science. Pacific Grove, California.CiteSeerX 10.1.1.26.2787.
  23. ^abPeyton Jones, Simon L.;Wadler, Philip (January 1993).Imperative functional programming(PDF). 20th Annual ACM Symposium on Principles of Programming Languages. Charleston, South Carolina.CiteSeerX 10.1.1.53.2504.
  24. ^Brent YorgeyTypeclassopedia
  25. ^Stack overflow(8 Sep 2017) Defining a new monad in haskell raises no instance for Applicative
  26. ^Brent YorgeyMonoids
  27. ^"Applicative functor".HaskellWiki. Haskell.org. 7 May 2018.Archived from the original on 30 October 2018. Retrieved20 November 2018.
  28. ^abGibbard, Cale (30 December 2011)."Monads as containers".HaskellWiki. Haskell.org.Archived from the original on 14 December 2017. Retrieved20 November 2018.
  29. ^abPiponi, Dan (7 August 2006)."You Could Have Invented Monads! (And Maybe You Already Have.)".A Neighborhood of Infinity.Archived from the original on 24 October 2018. Retrieved16 October 2018.
  30. ^"Some Details on F# Computation Expressions". 21 September 2007. Retrieved9 October 2018.
  31. ^Giles, Brett (12 August 2013)."Lifting".HaskellWiki. Haskell.org.Archived from the original on 29 January 2018. Retrieved25 November 2018.
  32. ^abRivas, Exequiel; Jaskelioff, Mauro; Schrijvers, Tom (July 2015).From monoids to near-semirings: the essence of MonadPlus and Alternative(PDF). 17th International ACM Symposium on Principles and Practice of Declarative Programming. Siena, Italy.CiteSeerX 10.1.1.703.342.
  33. ^Swierstra, Wouter (2008)."Data types à la carte"(PDF). Functional Pearl.Journal of Functional Programming.18 (4). Cambridge University Press:423–436.CiteSeerX 10.1.1.101.4131.doi:10.1017/s0956796808006758.ISSN 1469-7653.S2CID 21038598.
  34. ^Kiselyov, Oleg (May 2012). Schrijvers, Tom; Thiemann, Peter (eds.).Iteratees(PDF). International Symposium on Functional and Logic Programming. Lecture Notes in Computer Science. Vol. 7294. Kobe, Japan: Springer-Verlag. pp. 166–181.doi:10.1007/978-3-642-29822-6_15.ISBN 978-3-642-29822-6.
  35. ^Uustalu, Tarmo; Vene, Varmo (July 2005). Horváth, Zoltán (ed.).The Essence of Dataflow Programming(PDF). First Summer School, Central European Functional Programming. Lecture Notes in Computer Science. Vol. 4164. Budapest, Hungary: Springer-Verlag. pp. 135–167.CiteSeerX 10.1.1.62.2047.ISBN 978-3-540-46845-5.
  36. ^Uustalu, Tarmo; Vene, Varmo (June 2008)."Comonadic Notions of Computation".Electronic Notes in Theoretical Computer Science.203 (5). Elsevier:263–284.doi:10.1016/j.entcs.2008.05.029.ISSN 1571-0661.
  37. ^Power, John; Watanabe, Hiroshi (May 2002)."Combining a monad and a comonad"(PDF).Theoretical Computer Science.280 (1–2). Elsevier:137–162.CiteSeerX 10.1.1.35.4130.doi:10.1016/s0304-3975(01)00024-x.ISSN 0304-3975.
  38. ^Gaboardi, Marco; Katsumata, Shin-ya; Orchard, Dominic; Breuvart, Flavien; Uustalu, Tarmo (September 2016).Combining Effects and Coeffects via Grading(PDF). 21st ACM International Conference on Functional Programming. Nara, Japan: Association for Computing Machinery. pp. 476–489.doi:10.1145/2951913.2951939.ISBN 978-1-4503-4219-3.

External links

[edit]
The WikibookHaskell has a page on the topic of:Understanding monads

HaskellWiki references:

  • "All About Monads" (originally by Jeff Newbern) — A comprehensive discussion of all the common monads and how they work in Haskell; includes the "mechanized assembly line" analogy.
  • "Typeclassopedia" (originally by Brent Yorgey) — A detailed exposition of how the leading typeclasses in Haskell, including monads, interrelate.

Tutorials:

Interesting cases:

Gang of Four
patterns
Creational
Structural
Behavioral
Concurrency
patterns
Architectural
patterns
Other
patterns
Books
People
Communities
See also
Central concepts
Topics
Areas
Phenomena
Formalism
Formal systems
Concepts
See also
Retrieved from "https://en.wikipedia.org/w/index.php?title=Monad_(functional_programming)&oldid=1320340311"
Categories:
Hidden categories:

[8]ページ先頭

©2009-2025 Movatter.jp