Monads compared to InputRanges?

Max Klyga email at domain.com
Tue Dec 3 13:51:20 PST 2013


On 2013-12-03 02:45:44 +0000, Shammah Chancellor said:

> I'm not particularly familiar with the syntax being used in the variet 
> of monad examples.   I'm trying to figure out how this is different 
> from UFCS on InputRanges.   It seems like std.algorithm implements 
> something which accomplished the same thing, but much easier to 
> understand?
> 
> Can somebody maybe do a compare and contrast for me?
> 
> -Shammah

Monads and input ranges are different things. I'll try to briefly 
explain monads. Hope this will not worsen the situation by being too 
confusing.

InputRanges provide a generic way for iterating over something.

UFCS can be used to create a range interface on things that do not provide it.

Monads are an abstraction for composing things within some context 
(concatenating lists, composing operations on nullable values, 
composing asynchronous operations). That sounds a bit too general and 
vague, because it is. One can think about as a design pattern.
Monad has two operations:
  - make a monad out of a value
  - apply a function that takes a value and returns a new monad of the 
same kind to value inside a monad

second operation has a different meaning for different monad kinds but 
generally it means 'execute this code within current context'

for nullable values this means 'execute only if there exist a value'
for asynchronous operations this means 'execute this when the value is ready'

This operation is commonly named 'bind' or 'flatMap'

Some languages provide syntax sugar for monads (Scala's for, Haskell's do)
Monads are easier to understand once you've seen enough examples of 
things that are monads.

Suppose you have a list of movies and want to produce a list of names 
of all actors stating in those movies.
In scala you would typically write something like this:

	for (movie <- movies; actor <- movie.actors) yield actor.name

Compiler rewrites that to

	movies.flatMap(movie => movie.actors).map(actor => actor.name)
                           ^
                            ---------- this function takes a list 
element and returns a new list, effectively creating a list of lists 
and then flattening it by concatenating all the lists into one, hence 
the name 'flatMap'. It transforms and then flattens.

Another popular example for Monads are optional values (similar to 
nullables but forcing you to check for presence of value and explicitly 
avoiding null dereferencing)

A common pattern for working with optional values is returning null 
from your function if your input is null

So if say we are parsing JSON and we want to process only values that 
contain certain field, that in turn contains another field. Example in 
pseudo-scala:

	for (value <- json.get("value"); // type of value is Option(JsonNode) 
meaning that actual json node might be absent
	       anotherValue <- value.get("another")) // this is executed only 
if value is present
		doSomethingFancy(anotherValue) // ditto

and again, compiler will rewrite this into

	json.get("value").flatMap(value => 
value.get("another")).foreach(anotherValue => 
doSomethingFancy(anotherValue))

Once again we see that flat map is used. The pattern is same - get the 
value out of the box, transform it to another box of the same kind in 
the context meaningful for this particular box kind

So the main benefit is being able to compose things in a consistent 
way. Once you grasp the whole idea its fun finding out that some thing 
you've been doing can be viewed as a monad. People created quite a lot 
of different monads to this date.



More information about the Digitalmars-d-learn mailing list