Skip to content

Instantly share code, notes, and snippets.

@channingwalton
Last active December 14, 2015 14:58
Show Gist options
  • Save channingwalton/5104053 to your computer and use it in GitHub Desktop.
Save channingwalton/5104053 to your computer and use it in GitHub Desktop.
Iterate a list of functions A => Option[B] returning the first Some
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)
}
@larsrh
Copy link

larsrh commented Mar 6, 2013

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)

@channingwalton
Copy link
Author

Fixed

@seanparsons
Copy link

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

@missingfaktor
Copy link

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.

@bmjames
Copy link

bmjames commented Mar 7, 2013

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment