1

Suppose I have a function f: (Int, Int, Int) => String. I can easily apply it to three parameters of type Option[Int]:

def foo(f: (Int, Int, Int) => String,
        ox: Option[Int],
        oy: Option[Int],
        oz: Option[Int]): Option[String] = ox <*> (oy <*> (oz <*> f.curried.some))  

Suppose now that I need to apply f to the first three elements of list ois: List[Option[Int]]. For example:

List() => None
List(1.some, 2.some) => None
List(1.some, None, 2.some, 3.some) => None
List(1.some, 2.some, 3.some, 4.some) => Some(f(1, 2, 3))
List(1.some, 2.some, 3.some, None) => Some(f(1, 2, 3))

How would you implement it ?

Michael
  • 41,026
  • 70
  • 193
  • 341
  • If the fourth element of the list is None, what result do you want? With sequence, you get None. – Didier Dupont Mar 26 '15 at 14:26
  • @DidierDupont Thank you. I was wrong. For `List(1.some, 2.some, 3.some, None)` I need to get `Some(f(1, 2, 3))`. I will update the question. – Michael Mar 26 '15 at 14:31

1 Answers1

4

You could use Option, take, flatten, and collect together for a pretty clean version:

def foo(f: (Int, Int, Int) => String, ois: List[Option[Int]]) = 
    Option(ois.take(3).flatten) collect {
        case List(a, b, c) => f(a, b, c)
}

ois.take(3).flatten will only match List(a,b,c) if the first three elements are Some. You wrap the variable in Option to enable the desired collect semantics (such that the partial function miss will return None, and the return of the partial function will be wrapped in Some).

Ben Reich
  • 16,222
  • 2
  • 38
  • 59
  • Thank you. It looks pretty neat ! I am just wondering what if I have `List[A[Int]]` where `A` is another applicative. – Michael Mar 26 '15 at 14:39
  • 1
    @Michael You can replace `Option(ois.take(3).flatten)` with `ois.take(3).sequence` – Kolmar Mar 26 '15 at 14:41
  • 1
    This is a version for generic typeclasses: `def foo[A[_] : Applicative](f: (Int, Int, Int) => String, ois: List[A[Int]]): A[String] = ois.take(3).sequence.map { case List(a,b,c) => f(a,b,c) }` (There is no `collect` on applicatives, but `map` is enough) – Kolmar Mar 26 '15 at 14:56