Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-

Monads

Name: Anonymous 2010-12-28 10:37

WTF are they and should I care?

Name: Anonymous 2010-12-28 11:14

Name: Anonymous 2010-12-28 12:31

>>1
Consider a list of elements. It would be nice to have a function like List<R> map<T, R>(List<T> source, Func<T, R> f), which takes a List of T, applies the supplied function to each element, and returns the list of result.

Consider a type, instances of which can hold an element or no elements. For such a type it would be useful to have a function like Nullable<R> map<T, R>(Nullable<T> source, Func<T, R> f), which either returns a new Nullable containing the result of function application, or a Nullable<R>.Empty if the source nullable is empty.

Consider a type representing a delayed computation. It too should have a function like Future<R> map<T, R>(Future<T> source, Func<T, R> f), which passes this function to a separate thread, which then adds it to the list of transformation it has to perform.

Do you see a pattern? It is called Functor (not to be confused with C++ "functors"). A Functor is a function like that (it's usually called "bind", because it binds the argument of the given function to the items contained within) plus the constructor that constructs an instance of a functor from a single object of the base type.

Note that being a Functor is like supporting an interface -- it says what you can do with the stuff, not what you can't do. For example, our Future<T> would also support the T force<T>(Future<T> source) method, which blocks execution of the current thread until the worker thread produces the result and returns it. And so on -- it's like IComparable -- it says that you are allowed to compare stuff, but doesn't prevent you from doing whatever else you might want.

Also note that you can't properly implement Functor as a real interface in languages like C# or Java because they lack higher-order generics (you want something like IFunctor<TFunctor<TItem>>).

Finally, note that a proper functor obeys some simple laws: if you have a valid chain f(g(x)), you can wrap it in your functor at any point, starting with x, or with g(x), or with f(g(x)), and get exactly the same resulting functor. In other words, functors must preserve function application.

For example, a functor on integers which increment the value each time bind is called, is not a proper functor.

OK, now observe the following expression

var x = Nullable(10).bind(x => Nullable(20).bind(y => x + y))

If we can get it to work, then we can perform arbitrary calculations in our functors! But oh no, instead of Nullable(30) it returns Nullable(Nullable(30))! What do?

Monad<R> bind<T, R>(Monad<T> source, Func<T, Monad<R>> f)

BAM! If we require the function to wrap the value in our, well, it's Monad now!, it can decide to not wrap it excessively, and our code now works!

That is basically all.

Why should you care? Well, why should you care about the Visitor pattern for example? You have a problem, you look at it and suddenly realize that the solution should be an implementation of a Visitor pattern -- now you know how to call your functions, what properties they should have, what to write in comments so that some other programmer could immediately understand the purpose of the code, etc. It doesn't even matter if your language supports double dispatch natively -- it's about the structure of the code.

Functors and Monads are much more pervasive than the lesser patterns like Visitor, so it pays to be able to recognize them in your code.

Also, this trick we did when switching from Functor to Monad is nice and occasionally useful -- for example, I was writing an html simplifier recently, and suddenly discovered that the code gets much cleaner if instead of a single node each of my functions returns a list of nodes, to be integrated in the parent node.

Name: Anonymous 2010-12-28 13:07

>>3
Wow, that's an incredible load of bullshit.

Name: Anonymous 2010-12-28 16:14

>>4
... and it's just a perfect example of why you should never tell anybody anything.

Name: Anonymous 2010-12-28 18:54

>>3
occasionally useful
Entire post summed up in two words.

Name: Anonymous 2010-12-28 21:21

>>1
If you wanna know what monads in haskell are don't make the mistake of reading one of the various mini tutorials explaining monads.

Instead, simply learn how haskell typeclasses work and then look at the monad typeclass.

Name: Anonymous 2010-12-28 21:46

Name: Anonymous 2010-12-28 22:23

Haskell uses this call-by-name semantics, that makes it very hard to write anything but factorials, so crazy people from Glasgow invented these "monads" as an ad-hoc work around, when one needs usual call-by-value. Other than that, moands are just another incomplete interface to continuations.

Name: Anonymous 2010-12-28 22:26

>>9
Difference between call-by-name and call-by-value is explained in SICP under the "normal order evaluation" and "applicative order evaluation". So, please, read your SICP.

Name: Anonymous 2010-12-28 22:28

>>9
Any sufficiently complicated Haskell or ML program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of LISP.

Name: Anonymous 2010-12-28 22:41

>>9
Any sufficiently complicated Perl, Ruby, Python, Haskell, ML, C, C++, Java, JavaScript, PHP, Scheme, Common LISP, Arc, C#, Basic, Cobol, Smalltalk, IO, Scala, Groovy, Fortran, Go, D or *insert-more-languages-here* program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Common LISP.

Name: Anonymous 2010-12-28 23:04

Any sufficiently complicated Common LISP program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Common LISP.

Name: Anonymous 2010-12-28 23:49

A commonly contained Sufficient SPECIFY bug implements any half, informally-ridden, slow, ad-hoc common of lisp of Complicated PROGRAM.

Name: Anonymous 2010-12-29 0:49

Any sufficiently complicated Common LISP program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Perl.

Name: Anonymous 2010-12-29 2:47

Any sufficiently complicated Haskell program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Perl 6 operators.

Name: Anonymous 2010-12-29 5:06

MONAD MY ANUS

Name: Anonymous 2010-12-29 5:15

>>9
Haskell uses call-by-need, not call-by-name.

Name: Anonymous 2010-12-29 5:38

>>18
Haskell uses lazy evaluation, not call-by-whatever.
Lazy evaluation is sharing/elimination (like in c-b-need) + normal order evaluation [but only until HNF] + monads.

Name: Anonymous 2010-12-29 9:59

HASKELL. HASKELL NOMADS

Name: Anonymous 2011-02-03 7:16

Name: Anonymous 2011-02-17 20:24

dubz

Don't change these.
Name: Email:
Entire Thread Thread List