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!
== More examples == === Identity monad === The simplest monad is the '''Identity monad''', which just annotates plain values and functions to satisfy the monad laws: '''newtype''' Id T = T unit(x) = x (x >>= f) = f(x) <code>Identity</code> does actually have valid uses though, such as providing a [[base case (recursion)|base case]] for recursive [[monad transformer]]s. It can also be used to perform basic variable assignment within an imperative-style block.{{efn|In category theory, the <code>Identity</code> monad can also be viewed as emerging from [[adjunction (category theory)|adjunction]] of any functor with its inverse.}}{{citation needed|date=October 2018}} === Collections === Any collection with a proper {{mvar|append}} is already a monoid, but it turns out that <code>List</code> is not the only [[Collection (abstract data type)|collection]] that also has a well-defined {{mvar|join}} and qualifies as a monad. One can even mutate <code>List</code> into these other monadic collections by simply imposing special properties on {{mvar|append}}:{{efn|Category theory views these collection monads as adjunctions between the [[free functor]] and different functors from the [[category of sets]] to the [[category of monoids]].}}{{efn|name= monoid|1= Here the task for the programmer is to construct an appropriate monoid, or perhaps to choose a monoid from a library.}} {| class="wikitable" |- ! rowspan=2 | Collection !! colspan=3 | Monoid properties !! colspan=2 | Combinatoric properties |- ! Commutative? !! Idempotent? !! Details !! Ordered? !! Unique items? |- | List || {{No}} || {{No}} || [[Free monoid]] || {{Yes}} || {{No}} |- | Finite [[multiset]] || {{Yes}} || {{No}} || || {{No}} || {{No}} |- | Finite [[set (mathematics)|set]] || {{Yes}} || {{Yes}} || || {{No}} || {{Yes}} |} === IO monad (Haskell) <span id="IO monad"></span> === As already mentioned, pure code should not have unmanaged side effects, but that does not preclude a program from ''explicitly'' describing and managing effects. This idea is central to Haskell's '''IO monad''', where an object of type <code>IO a</code> can be seen as describing an action to be performed in the world, optionally providing information about the world of type <code>a</code>. An action that provides no information about the world has the type <code>IO ()</code>, "providing" the dummy value <code>()</code>. When a programmer binds an <code>IO</code> 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.).<ref name="PeytonWadler1993">{{cite conference | author-link1 = Simon Peyton Jones | author-link2 = Philip Wadler | last1 = Peyton Jones | first1 = Simon L. | last2 = Wadler | first2 = Philip | title = Imperative functional programming | date = January 1993 | conference = 20th Annual ACM Symposium on Principles of Programming Languages | location = Charleston, South Carolina | url = https://www.microsoft.com/en-us/research/wp-content/uploads/1993/01/imperative.pdf | citeseerx = 10.1.1.53.2504}}</ref> 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 wider [[file system]], including one that checks whether a file exists and another that deletes a file. Their two type signatures are: <syntaxhighlight lang="haskell"> doesFileExist :: FilePath -> IO Bool removeFile :: FilePath -> IO () </syntaxhighlight> The first is interested in whether a given file really exists, and as a result, outputs a [[Boolean data type|Boolean value]] within the <code>IO</code> monad. The second function, on the other hand, is only concerned with acting on the file system so the <code>IO</code> container it outputs is empty. <code>IO</code> 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]]: <syntaxhighlight lang="haskell"> main :: IO () main = do putStrLn "Hello, world!" putStrLn "What is your name, user?" name <- getLine putStrLn ("Nice to meet you, " ++ name ++ "!") </syntaxhighlight> Desugared, this translates into the following monadic pipeline (<code>>></code> in Haskell is just a variant of {{mvar|bind}} for when only monadic effects matter and the underlying result can be discarded): <syntaxhighlight lang="haskell"> main :: IO () main = putStrLn "Hello, world!" >> putStrLn "What is your name, user?" >> getLine >>= (\name -> putStrLn ("Nice to meet you, " ++ name ++ "!")) </syntaxhighlight> === Writer monad (JavaScript) <span id="Writer monad"></span> === Another common situation is keeping a [[log file]] or otherwise reporting a program's progress. Sometimes, a programmer may want to log even more specific, technical data for later [[profiling (computer programming)|profiling]] or [[debugging]]. The '''Writer 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 a <code>Writer</code> monad in [[JavaScript]]. First, an array (with nested tails) allows constructing the <code>Writer</code> type as a [[linked list]]. The underlying output value will live in position 0 of the array, and position 1 will implicitly hold a chain of auxiliary notes: <syntaxhighlight lang="Javascript">const writer = value => [value, []];</syntaxhighlight> Defining {{mvar|unit}} is also very simple: <syntaxhighlight lang="Javascript">const unit = value => [value, []];</syntaxhighlight> Only {{mvar|unit}} is needed to define simple functions that output <code>Writer</code> objects with debugging notes: <syntaxhighlight lang="Javascript"> const squared = x => [x * x, [`${x} was squared.`]]; const halved = x => [x / 2, [`${x} was halved.`]]; </syntaxhighlight> A true monad still requires {{mvar|bind}}, but for <code>Writer</code>, this amounts simply to concatenating a function's output to the monad's linked list: <syntaxhighlight lang="Javascript"> const bind = (writer, transform) => { const [value, log] = writer; const [result, updates] = transform(value); return [result, log.concat(updates)]; }; </syntaxhighlight> The sample functions can now be chained together using {{mvar|bind}}, but defining a version of monadic composition (called <code>pipelog</code> here) allows applying these functions even more succinctly: <syntaxhighlight lang="Javascript"> const pipelog = (writer, ...transforms) => transforms.reduce(bind, writer); </syntaxhighlight> The final result is a clean separation of concerns between stepping through computations and logging them to audit later: <syntaxhighlight lang="Javascript"> pipelog(unit(4), squared, halved); // Resulting writer object = [8, ['4 was squared.', '16 was halved.']] </syntaxhighlight> ===Environment monad=== {{See also|Monad (category theory)#The environment monad}} An environment monad (also called a ''reader monad'' and a ''function monad'') allows a computation to depend on values from a shared environment. The monad type constructor maps a type {{mvar|T}} to functions of type {{math|''E'' β ''T''}}, where {{mvar|E}} is the type of the shared environment. The monad functions are: <math display="block">\begin{array}{ll} \text{return} \colon & T \rarr E \rarr T = t \mapsto e \mapsto t \\ \text{bind} \colon & (E \rarr T) \rarr (T \rarr E \rarr T') \rarr E \rarr T' = r \mapsto f \mapsto e \mapsto f \, (r \, e) \, e \end{array} </math> The following monadic operations are useful: <math display="block">\begin{array}{ll} \text{ask} \colon & E \rarr E = \text{id}_E \\ \text{local} \colon & (E \rarr E) \rarr (E \rarr T) \rarr E \rarr T = f \mapsto c \mapsto e \mapsto c \, (f \, e) \end{array} </math> The {{math|ask}} operation is used to retrieve the current context, while {{math|local}} 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; {{math|return}} and {{math|bind}} are equivalent to the {{math|K}} and {{math|S}} combinators, respectively, in the [[SKI combinator calculus]]. ===State monads=== {{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 type <code>s</code>) along with a return value (of type <code>t</code>). This is similar to an environment monad, except that it also returns a new state, and thus allows modeling a ''mutable'' environment. <syntaxhighlight lang="haskell"> type State s t = s -> (t, s) </syntaxhighlight> Note that this monad takes a type parameter, the type of the state information. The monad operations are defined as follows: <syntaxhighlight lang="haskell"> -- "return" produces the given value without changing the state. return x = \s -> (x, s) -- "bind" modifies m so that it applies f to its result. m >>= f = \r -> let (x, s) = m r in (f x) s </syntaxhighlight> Useful state operations include: <syntaxhighlight lang="haskell"> get = \s -> (s, s) -- Examine the state at this point in the computation. put s = \_ -> ((), s) -- Replace the state. modify f = \s -> ((), f s) -- Update the state </syntaxhighlight> Another operation applies a state monad to a given initial state: <syntaxhighlight lang="haskell"> runState :: State s a -> s -> (a, s) runState t s = t s </syntaxhighlight> do-blocks in a state monad are sequences of operations that can examine and update the state data. Informally, a state monad of state type {{mvar|S}} maps the type of return values {{mvar|T}} into functions of type <math>S \rarr T \times S</math>, where {{mvar|S}} is the underlying state. The {{math|return}} and {{math|bind}} function are: :<math>\begin{array}{ll} \text{return} \colon & T \rarr S \rarr T \times S = t \mapsto s \mapsto (t, s) \\ \text{bind} \colon & (S \rarr T \times S) \rarr (T \rarr S \rarr T' \times S) \rarr S \rarr T' \times S \ = m \mapsto k \mapsto s \mapsto (k \ t \ s') \quad \text{where} \; (t, s') = m \, s \end{array} </math>. 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 any [[cartesian closed category]] by definition. ===Continuation monad=== A [[continuation]] monad{{efn|name= mccan|1= The reader may wish to follow McCann's thread<ref name=so3322540 /> and compare it with the Types below.}} with return type {{mvar|R}} maps type {{mvar|T}} into functions of type <math>\left(T \rarr R \right) \rarr R</math>. It is used to model [[continuation-passing style]]. The return and bind functions are as follows: :<math>\begin{array}{ll} \text{return} \colon &T \rarr \left(T \rarr R \right) \rarr R = t \mapsto f \mapsto f \, t\\ \text{bind} \colon &\left(\left(T \rarr R \right) \rarr R \right) \rarr \left(T \rarr \left(T' \rarr R \right) \rarr R \right) \rarr \left(T' \rarr R \right) \rarr R = c \mapsto f \mapsto k \mapsto c \, \left(t \mapsto f \, t \, k \right) \end{array}</math> The [[call-with-current-continuation]] function is defined as follows: :<math>\text{call/cc} \colon \ \left(\left(T \rarr \left(T' \rarr R \right) \rarr R \right) \rarr \left(T \rarr R \right) \rarr R \right) \rarr \left(T \rarr R \right) \rarr R = f \mapsto k \mapsto \left(f \left(t \mapsto x \mapsto k \, t \right) \, k \right)</math> === Program logging === The following code is pseudocode. {{anchor|Sample adjunct supposition}}Suppose we have two functions <code>foo</code> and <code>bar</code>, with types <syntaxhighlight lang="haskell"> foo : int -> int bar : int -> int </syntaxhighlight> That is, both functions take in an integer and return another integer. Then we can apply the functions in succession like so: <syntaxhighlight lang="haskell"> foo (bar x) </syntaxhighlight> Where the result is the result of <code>foo</code> applied to the result of <code>bar</code> applied to <code>x</code>. But suppose we are debugging our program, and we would like to add logging messages to <code>foo</code> and <code>bar</code>. So we change the types as so: <syntaxhighlight lang="haskell"> foo : int -> int * string bar : int -> int * string </syntaxhighlight> 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 longer [[Function composition|compose]] <code>foo</code> and <code>bar</code>, as their input type <code>int</code> is not compatible with their output type <code>int * string</code>. And although we can again gain composability by modifying the types of each function to be <code>int * string -> int * string</code>, 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. {{anchor|pasteInAdjunction}} Instead, let us define a helper function to abstract away this boilerplate for us: <syntaxhighlight lang="haskell"> bind : int * string -> (int -> int * string) -> int * string </syntaxhighlight> <code>bind</code> takes in an integer and string tuple, then takes in a function (like <code>foo</code>) 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, in <code>bind</code>. Now we have regained some composability. For example: <syntaxhighlight lang="haskell"> bind (bind (x,s) bar) foo </syntaxhighlight> Where <code>(x,s)</code> is an integer and string tuple.{{efn|name= paste|1= In this case, the <code>bind</code> has ''pasted'' in a <code>string</code> where previously only an <code>integer</code> had been; that is, the programmer has constructed an [[Adjoint functors|adjunction]]: a tuple <code>(x,s)</code>, denoted <code>int * string</code> in the pseudocode [[#pasteInAdjunction|Β§ above]].}} To make the benefits even clearer, let us define an infix operator as an alias for <code>bind</code>: <syntaxhighlight lang="haskell"> (>>=) : int * string -> (int -> int * string) -> int * string </syntaxhighlight> So that <code>t >>= f</code> is the same as <code>bind t f</code>. Then the above example becomes: <syntaxhighlight lang="haskell"> ((x,s) >>= bar) >>= foo </syntaxhighlight> Finally, we define a new function to avoid writing <code>(x, "")</code> every time we wish to create an empty logging message, where <code>""</code> is the empty string. <syntaxhighlight lang="haskell"> return : int -> int * string </syntaxhighlight> Which wraps <code>x</code> in the tuple described above. The result is a pipeline for logging messages: <syntaxhighlight lang="haskell"> ((return x) >>= bar) >>= foo </syntaxhighlight> That allows us to more easily log the effects of <code>bar</code> and <code>foo</code> on <code>x</code>. <code>int * string</code> denotes a pseudo-coded '''monadic value'''.{{efn|name= paste}} <code>bind</code> and <code>return</code> are analogous to the corresponding functions of the same name. In fact, <code>int * string</code>, <code>bind</code>, and <code>return</code> form a monad. === Additive monads === An '''additive monad''' is a monad endowed with an additional closed, associative, binary operator '''mplus''' and an [[identity element]] under {{mvar|mplus}}, called '''mzero'''. The <code>Maybe</code> monad can be considered additive, with <code>Nothing</code> as {{mvar|mzero}} and a variation on the [[logical disjunction|OR]] operator as {{mvar|mplus}}. <code>List</code> is also an additive monad, with the empty list <code>[]</code> acting as {{mvar|mzero}} and the concatenation operator <code>++</code> as {{mvar|mplus}}. Intuitively, {{mvar|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 an [[absorbing element|absorber]] for {{mvar|bind}}, returning {{mvar|mzero}} whenever bound to a monadic function. This property is two-sided, and {{mvar|bind}} will also return {{mvar|mzero}} when any value is bound to a monadic [[zero function]]. In category-theoretic terms, an additive monad qualifies once as a monoid over monadic functions with {{mvar|bind}} (as all monads do), and again over monadic values via {{mvar|mplus}}.<ref name="RJS2015">{{cite conference |last1=Rivas |first1=Exequiel |last2=Jaskelioff |first2=Mauro |last3=Schrijvers |first3=Tom |date=July 2015 |title=From monoids to near-semirings: the essence of MonadPlus and Alternative |url=https://usuarios.fceia.unr.edu.ar/~mauro/pubs/FromMonoidstoNearsemirings.pdf |conference=17th International ACM Symposium on Principles and Practice of Declarative Programming |location=Siena, Italy |citeseerx=10.1.1.703.342}}</ref>{{efn|Algebraically, the relationship between the two (non-commutative) monoid aspects resembles that of a [[near-semiring]], and some additive monads do qualify as such. However, not all additive monads meet the [[distributive property|distributive]] laws of even a near-semiring.<ref name="RJS2015" />}} === Free monads === Sometimes, the general outline of a monad may be useful, but no simple pattern recommends one monad or another. This is where a '''free monad''' comes in; as a [[free object]] in the category of monads, it can represent monadic structure without any specific constraints beyond the monad laws themselves. Just as a [[free 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 the <code>Just</code> and <code>Nothing</code> markers, the <code>Maybe</code> monad is in fact a free monad. The <code>List</code> monad, on the other hand, is not a free monad since it brings extra, specific facts about lists (like {{mvar|append}}) into its definition. One last example is an abstract free monad: <syntaxhighlight lang="haskell"> data Free f a = Pure a | Free (f (Free f a)) unit :: a -> Free f a unit x = Pure x bind :: Functor f => Free f a -> (a -> Free f b) -> Free f b bind (Pure x) f = f x bind (Free x) f = Free (fmap (\y -> bind y f) x) </syntaxhighlight> Free monads, however, are ''not'' restricted to a linked-list like in this example, and can be built around other structures like [[tree (data structure)|tree]]s. 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 and [[interpreter (computing)|interpreter]]s as a result.<ref name="Swierstra2008">{{cite journal |last=Swierstra |first=Wouter |year=2008 |title=Data types Γ la carte |url=https://www.cs.ru.nl/~W.Swierstra/Publications/DataTypesALaCarte.pdf |department=Functional Pearl |journal=Journal of Functional Programming |publisher=Cambridge University Press |volume=18 |issue=4 |pages=423β436 |citeseerx=10.1.1.101.4131 |doi=10.1017/s0956796808006758 |doi-broken-date=1 November 2024 |issn=1469-7653 |s2cid=21038598}}</ref> Others have applied them to more dynamic, operational problems too, such as providing [[iteratee]]s within a language.<ref name="Kiselyov2012">{{cite conference |last=Kiselyov |first=Oleg |date=May 2012 |editor1-last=Schrijvers |editor1-first=Tom |editor2-last=Thiemann |editor2-first=Peter |title=Iteratees |url=http://okmij.org/ftp/Haskell/Iteratee/describe.pdf |conference=International Symposium on Functional and Logic Programming |series=Lecture Notes in Computer Science |location=Kobe, Japan |publisher=Springer-Verlag |volume=7294 |pages=166β181 |doi=10.1007/978-3-642-29822-6_15 |isbn=978-3-642-29822-6}}</ref> === Comonads === Besides generating monads with extra properties, for any given monad, one can also define a '''comonad'''. 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 the [[categorical dual]] of a monad, which loosely means that it will have the same required components, only with the direction of the type signatures ''reversed''. Starting from the {{mvar|bind}}-centric monad definition, a comonad consists of: * A type constructor {{mvar|W}} that marks the higher-order type {{mvar|W T}} * The dual of {{mvar|unit}}, called '''counit''' here, extracts the underlying value from the comonad: counit(wa) : W T β T * A reversal of {{mvar|bind}} (also represented with <code>=>></code>) that '''extend'''s a chain of reducing functions: (wa =>> f) : (W U, W U β T) β W T{{efn|In Haskell, {{mvar|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 of {{mvar|bind}}.}} {{mvar|extend}} and {{mvar|counit}} must also satisfy duals of the monad laws: counit β '''(''' (wa =>> f) β wb ''')''' β f(wa) β b wa =>> counit β wa wa '''(''' (=>> 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 of {{mvar|join}}: * '''duplicate''' takes an already comonadic value and wraps it in another layer of comonadic structure: duplicate(wa) : W T β W (W T) While operations like {{mvar|extend}} are reversed, however, a comonad does ''not'' reverse functions it acts on, and consequently, comonads are still functors with {{mvar|map}}, not [[cofunctor]]s. The alternate definition with {{mvar|duplicate}}, {{mvar|counit}}, and {{mvar|map}} 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) wx duplicate wa β wa =>> wx wa =>> f(wx) β ((map f) β duplicate) wa A simple example is the '''Product comonad''', which outputs values based on an input value and shared environment data. In fact, the <code>Product</code> comonad is just the dual of the <code>Writer</code> monad and effectively the same as the <code>Reader</code> monad (both discussed below). <code>Product</code> and <code>Reader</code> differ only in which function signatures they accept, and how they complement those functions by wrapping or unwrapping values. A less trivial example is the '''Stream comonad''', which can be used to represent [[stream (computing)|data stream]]s and attach filters to the incoming signals with {{mvar|extend}}. In fact, while not as popular as monads, researchers have found comonads particularly useful for [[stream processing]] and modeling [[dataflow programming]].<ref name="UustaluVenu2005">{{cite conference |last1=Uustalu |first1=Tarmo |last2=Vene |first2=Varmo |date=July 2005 |editor-last=HorvΓ‘th |editor-first=ZoltΓ‘n |title=The Essence of Dataflow Programming |url=http://www.cs.ioc.ee/~tarmo/papers/cefp05.pdf |conference=First Summer School, Central European Functional Programming |series=Lecture Notes in Computer Science |location=Budapest, Hungary |publisher=Springer-Verlag |volume=4164 |pages=135β167 |citeseerx=10.1.1.62.2047 |isbn=978-3-540-46845-5}}</ref><ref name="UustaluVenu2008">{{cite journal |last1=Uustalu |first1=Tarmo |last2=Vene |first2=Varmo |date=June 2008 |title=Comonadic Notions of Computation |journal=Electronic Notes in Theoretical Computer Science |publisher=Elsevier |volume=203 |issue=5 |pages=263β284 |doi=10.1016/j.entcs.2008.05.029 |issn=1571-0661 |doi-access=free}}</ref> Due to their strict definitions, however, one cannot simply move objects back and forth between monads and comonads. As an even higher abstraction, [[arrow (computer science)|arrow]]s can subsume both structures, but finding more granular ways to combine monadic and comonadic code is an active area of research.<ref name="PowerWatanabe2002">{{cite journal |last1=Power |first1=John |last2=Watanabe |first2=Hiroshi |date=May 2002 |title=Combining a monad and a comonad |url=https://core.ac.uk/download/pdf/82680163.pdf |journal=Theoretical Computer Science |publisher=Elsevier |volume=280 |issue=1β2 |pages=137β162 |citeseerx=10.1.1.35.4130 |doi=10.1016/s0304-3975(01)00024-x |issn=0304-3975}}</ref><ref name="GaboardiEtAl2016">{{cite conference |last1=Gaboardi |first1=Marco |last2=Katsumata |first2=Shin-ya |last3=Orchard |first3=Dominic |last4=Breuvart |first4=Flavien |last5=Uustalu |first5=Tarmo |date=September 2016 |title=Combining Effects and Coeffects via Grading |url=https://www.acsu.buffalo.edu/~gaboardi/publication/GaboardiEtAlicfp16.pdf |conference=21st ACM International Conference on Functional Programming |location=Nara, Japan |publisher=Association for Computing Machinery |pages=476β489 |doi=10.1145/2951913.2951939 |isbn=978-1-4503-4219-3}}</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)