monads - How to compose functions that return Option[List] in Scala? -
suppose have 2 functions orders , order items:
def getorders(): option[list[int]] = ... def getorderitems(orderid: int): option[list[int]] = ...
note both functions return option[list] since each function may fail.
now option of list of order items follows:
- return
some[list]if both functions returnsomeand noneif of them returns none.
i tried compose these functions for (see below) did not work.
val allorderitems = { orderids <- getorders(); orderid <- orderids; orderitems <- getorderitems(orderid) } yield orderitems how can build function getallorderitems():option[list[int]] using functions getorders , getorderitems ?
you want able turn middle 2 layers of option[list[option[list[int]]]] inside out, can options , lists next each other. operation called sequencing, , it's provided scalaz:
import scalaz._, scalaz._ val items: option[list[int]] = getorders.flatmap(_.map(getorderitems).sequence).map(_.flatten) you equivalently use traverse, combines map , sequence operations:
val items: option[list[int]] = getorders.flatmap(_ traverse getorderitems).map(_.flatten) if don't want use scalaz, write own (less polymorphic) sequence:
def sequence[a](xs: list[option[a]]) = xs.foldright(some(nil): option[list[a]]) { case (some(h), some(t)) => some(h :: t) case _ => none } and then:
val items: option[list[int]] = getorders.flatmap( orderids => sequence(orderids.map(getorderitems)) ).map(_.flatten) the monad transformation solution pretty straightforward (if you're willing use scalaz):
val items: option[list[int]] = ( { orderid <- listt(getorders) itemid <- listt(getorderitems(orderid)) } yield itemid ).underlying the nice thing approach don't have think need flatten, sequence, etc.—the plain old monadic operations want.
Comments
Post a Comment