组合 return 一个选项的函数
Composing functions that return an option
假设我有几个 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
)可以简化吗?
[A] Kleisli[Option, A, A]
是通过 Compose
的 Semigroup
,因此我们可以使用 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
我不确定似乎优先的实例来自哪里。
如果你想要组合幺半群(相对于 "run each and sum the results" 幺半群),你必须使用 Endomorphic
包装器:
import scalaz._, Scalaz._
val composed = fs.foldMap(Endomorphic.endoKleisli[Option, Int])
然后:
scala> composed.run(10)
res11: Option[Int] = Some(10)
kleisli 箭头的幺半群只需要一个输出类型的幺半群实例,而组合幺半群需要输入和输出类型相同,因此后者只能通过包装器使用是有道理的。
假设我有几个 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
)可以简化吗?
[A] Kleisli[Option, A, A]
是通过 Compose
的 Semigroup
,因此我们可以使用 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
我不确定似乎优先的实例来自哪里。
如果你想要组合幺半群(相对于 "run each and sum the results" 幺半群),你必须使用 Endomorphic
包装器:
import scalaz._, Scalaz._
val composed = fs.foldMap(Endomorphic.endoKleisli[Option, Int])
然后:
scala> composed.run(10)
res11: Option[Int] = Some(10)
kleisli 箭头的幺半群只需要一个输出类型的幺半群实例,而组合幺半群需要输入和输出类型相同,因此后者只能通过包装器使用是有道理的。