-
-
Save channingwalton/5104053 to your computer and use it in GitHub Desktop.
object play { | |
import scalaz._ | |
import Scalaz._ | |
def foo(i: Int) = if (i > 0) Some(i) else None | |
def boo(i: Int) = if (i <= 0) Some(0) else None | |
val l = foo _ :: boo _ :: Nil | |
l.foldMap(_.map(_.first)) apply -1 | |
//> res0: scalaz.@@[Option[Int],scalaz.Tags.First] = Some(0) | |
} |
Fixed
To avoid partially applying them you can easily convert foo and bar to vals:
val foo = (i: Int) => if (i > 0) Some(i) else None
May I attempt explaining what's happening? :-) (Might also be useful for those who see the gist in future.)
If you have a Monoid[A]
instance you can combine two values of type A
s and get a value of type A
.
Turns out there are three ways to combine Option
s. See lines 114-123 here - https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Semigroup.scala#L114.
We want the second one - FirstOption
. Hence the necessity of conversions.
Now, as Chris Marshall says, "monoids beget monoids". You can trivially derive Monoid[Option[A]]
instance from a Monoid[A]
instance, and you can trivially derive a Monoid[B => A]
instance from a Monoid[A]
instance. Combining these two, you can trivially derive a Monoid[B => Option[A]
instance from a Monoid[A]
instance. Which is what happens here.
You combine all the values in your list using the monoidal combination, and get a function which behaves as expected i.e. picks the result of first successful computation.
Nicely done. Purely to demonstrate that a new function is being produced (using the derived monoid as explained by Rahul), I might assign the result of the foldMap
to a value and then apply it with normal parens syntax.
If you don't want to define your methods to return
FirstOption[A]
, you can let them return "regular" options and then use:l.foldMap(_(1).first)