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 returnsome
and none
if 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