-
Notifications
You must be signed in to change notification settings - Fork 2
Either Monad
The Either type represents a value of one of two possible types. The possible
values are represented by Left and Right.
One possible usage of Either is similar to Option where, by convention,
Left is equivalent of None, i.e. it represents failure, while Right
assumes the role of Some. The difference between Option and Either is
in None/Left types where the former carries no information apart from the
fact that the computation failed. The latter, on the other hand, may also
carry additional message explaining what went wrong.
The other usage may be when one needs to return one of two distinct types. One example may be sorting books into list of authors and list of books without them.
Using example from Option monad, and replacing Option with Either
produces the following result:
import static hr.helix.monadologie.MonadComprehension.foreach
import static hr.helix.monadologie.monads.Either.left
import static hr.helix.monadologie.monads.Either.right
def safe(Closure action) {
try {
right(action())
} catch (e) {
left("${e.getClass().simpleName}: $e.message")
}
}
def check = { name -> name ? right(name) : left("file name not given") }
def load = { name -> safe { new File(name).text }},
parse = { text -> safe { text.tokenize()*.toInteger() }},
div = { a, b -> safe { a / b }}
def calc = { fileName ->
foreach {
file = takeFrom { check(fileName).right() }
text = takeFrom { load(file).right() }
data = takeFrom { parse(text).right() }
res = takeFrom { div(data).right() }
yield { res }
}
}
println calc(null) // file name validation failed
println calc("foo.txt") // file not found
def fileName = "/tmp/data"
new File(fileName).withWriter { w -> w << "aa bb" }
println calc(fileName) // number format exception
new File(fileName).withWriter { w -> w << "1 0" }
println calc(fileName) // division by zero
new File(fileName).withWriter { w -> w << "10 20" }
println calc(fileName)Here is example of another use case - processing data that have two distinct groups of values.
import static hr.helix.monadologie.monads.Either.left
import static hr.helix.monadologie.monads.Either.right
import static hr.helix.monadologie.monads.Either.lefts
import static hr.helix.monadologie.monads.Either.rights
def books = [
[title:"The Left Hand of Darkness", author:"Ursula K. LeGuin"],
[title:"Rendezvous with Rama", author:"Arthur C. Clarke"],
[title:"Star Maker", author:""],
[title:"The Forever War", author:"Joe Haldeman"],
[title:"Last and First Men"]
]
def sorted = books.collect {
it.author ? right(it.author) : left(it.title)
}
def authors = rights(sorted).unique(),
otherBooks = lefts(sorted)
println "List of authors:\n${authors.join(", ")}"
println "\nBooks with undisclosed authors:\n${otherBooks.join(", ")}"The real question here is, of course, who wrote Last and First Men and Star Maker?