2

假设我有一些类型的函数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))

我可以用mapand做到这一点reduce

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

它(composed以上)可以简化吗?

4

2 回答 2

3

如果您想要组合幺半群(而不是“运行每个并总结结果”幺半群),您必须使用Endomorphic包装器:

import scalaz._, Scalaz._

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

接着:

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

kleisli 箭头的 monoid 只需要输出类型的 monoid 实例,而组合 monoid 要求输入和输出类型相同,因此后者只能通过包装器获得是有道理的。

于 2015-07-13T13:59:36.940 回答
1

[A] Kleisli[Option, A, A]是一个Semigroupvia 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

我不确定似乎优先的实例来自哪里。

于 2015-07-13T09:50:23.023 回答