-
-
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 As and get a value of type A.
Turns out there are three ways to combine Options. 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)