2015-03-26 3 views
1

Предположим, у меня есть функция f: (Int, Int, Int) => String. Я могу легко применить его к трем параметрам типа Option[Int]:Как применить функцию к списку параметров в Scala?

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

Предположим теперь, что мне нужно применить f к первым трем элементам списка ois: List[Option[Int]]. Например:

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)) 

Как вы его реализуете?

+0

Если четвертый элемент списка None, какой результат вы хотите? С последовательностью вы получаете None. –

+0

@DidierDupont Спасибо. Я был неправ. Для 'List (1. some, 2. some, 3. some, None)' Мне нужно получить 'Some (f (1, 2, 3))'. Я уточню вопрос. – Michael

ответ

4

Вы можете использовать Option, take, flatten и collect вместе довольно чистой версии:

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 будет соответствовать только List(a,b,c), если первые три элемента Some. Вы обертываете переменную в Option, чтобы включить желаемую семантику collect (чтобы пропущенная частичная функция вернула None, а возврат частичной функции будет обернут в Some).

+0

Спасибо. Это выглядит довольно аккуратно! Мне просто интересно, что, если у меня есть 'List [A [Int]]', где 'A' является еще одним аппликативным. – Michael

+1

@Michael Вы можете заменить 'Option (ois.take (3) .flatten)' с 'ois.take (3) .sequence' – Kolmar

+0

@Kolmar Спасибо. Хорошая точка зрения. – Michael