Skip to content
Dinko Srkoč edited this page Aug 7, 2011 · 6 revisions

Translation of foreach Expressions

Monad comprehension is just a convenient notation, a helpful and more readable way of expressing nested iterations and function application. In a way it's just a syntax sugar, not unlike that of Java 1.5 for-each loop.

foreach expressions are expressed in terms of three functions: bind, fmap, and filter. The examples of the translation scheme are given below.

foreach expression with one generator

foreach {
    x = takeFrom { expr1 }
    yield { expr2 }
}

where x is a variable, expands to

expr1.fmap { x -> expr2 }

foreach expression with a generator and a guard

foreach {
    x = takeFrom { expr1 }
    guard { expr2 }
    yield { expr3 }
}

expands to

expr1.filter { x -> expr2 }.map { x -> expr3 }

Note: guards are not yet implemented for all monads

foreach expression with more than one generator

foreach {
    x = takeFrom { expr1 }
    y = takeFrom { expr2 }
    z = takeFrom { expr3 }
    yield { expr4 }
}

expands to

expr1.bind { x ->
    expr2.bind { y ->
        expr3.fmap { z -> expr4 }
    }
}

bind, fmap, and filter in Groovy terms

If we take Groovy List as being a monad, than the above mentioned functions might be implemented like this:

bind

List.metaClass.bind = { Closure fn ->
    delegate.inject([]) { acc, elem -> acc + fn(elem) }
}

where closure fn must return a list.

fmap

List.metaClass.fmap = { Closure fn ->
    delegate.collect(fn)
}

fmap is just a collect under disguise.

filter

List.metaClass.filter = { Closure fn ->
    delegate.findAll(fn)
}

filter is just a renamed findAll.

Clone this wiki locally