Составление функций, которые возвращают опцию

Предположим, у меня есть несколько функций типа Int => Option[Int]:

def foo(n: Int): Int => Option[Int] = {x => if (x == n) none else x.some}

val f0 = foo(0)
val f1 = foo(1)

Я могу составить их с >=> следующее:

val composed: Int => Option[Int] = Kleisli(f0) >=> Kleisli(f1)

Предположим, теперь мне нужно составить все функции из списка:

val fs: List[Int => Option[Int]] = List(0, 1, 2).map(n => foo(n))

Я могу сделать это с map а также reduce:

val composed: Int => Option[Int] = fs.map(f => Kleisli(f)).reduce(_ >=> _)

Может это (composed выше) быть упрощенным?

2 ответа

Решение

Если вам нужен моноид композиции (в отличие от моноида "запустите каждый и суммируйте результаты"), вам придется использовать Endomorphic обертка:

import scalaz._, Scalaz._

val composed = fs.foldMap(Endomorphic.endoKleisli[Option, Int])

А потом:

scala> composed.run(10)
res11: Option[Int] = Some(10)

Моноид для стрелок Клейсли требует только экземпляр моноида для типа вывода, в то время как моноид композиции требует, чтобы типы ввода и вывода были одинаковыми, поэтому имеет смысл, что последний доступен только через оболочку.

[A] Kleisli[Option, A, A] это Semigroup с помощью Compose так что мы можем использовать foldMap1 :

val composed: Int => Option[Int] = fs.foldMap1(f => Kleisli(f))

Интересно, что это не работает, хотя, если мы передаем правильный экземпляр явно, то это делает:

scala> val gs = NonEmptyList(fs.head, fs.tail: _*)
gs: scalaz.NonEmptyList[Int => Option[Int]] = NonEmptyList(<function1>, <function1>, <function1>)
scala> gs.foldMap1(f => Kleisli(f))(Kleisli.kleisliCompose[Option].semigroup[Int])
res20: scalaz.Kleisli[Option,Int,Int] = Kleisli(<function1>)
scala> gs.foldMap1(f => Kleisli(f))(Kleisli.kleisliCompose[Option].semigroup[Int]).apply(1)
res21: Option[Int] = None

Я не уверен, откуда приходит экземпляр, который, кажется, имеет приоритет.

Другие вопросы по тегам