【问题标题】:Composing functions that return an option组合返回选项的函数
【发布时间】:2015-07-13 09:25:39
【问题描述】:

假设我有几个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))

我可以用mapreduce 做到这一点:

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

可以简化(上面的composed)吗?

【问题讨论】:

    标签: scala monads scalaz kleisli


    【解决方案1】:

    如果您想要组合幺半群(而不是“运行每个并求和结果”幺半群),您必须使用 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 要求输入和输出类型相同,因此后者只能通过包装器获得是有道理的。

    【讨论】:

    • 好的,所以Endomorphic.endoKleisli[M, A] 仅适用于A => M[A] 如果M 有一个monad 实例。如果我有A => M[B] 怎么办?
    • 您的意思是要撰写A => M[B]B => M[C]C => M[D]等?然后你需要一个类型对齐的序列(目前不在 Scalaz 中)。
    • 谢谢。另一个问题只是为了确保我明白了:Endomorphic.endoKleisli[M, A] 是一个从A => M[A] 到包装器的函数,它有一个幺半群实例。对吗?
    • 是的,就是这样。
    • 谢谢。我相信我明白了。所以,现在我可以编写一个通用函数来链接A => M[A] 类型的函数:例如def chain[A, M[_] : Monad](fs: List[A => M[A]]) = fs foldMap (Endomorphic.endoKleisli[M, A])。我可能会问一个关于它的新问题。
    【解决方案2】:

    [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
    

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

    【讨论】:

    • 它无法按预期工作,因为|+| 未定义为&gt;=&gt;:例如val f = Kleisli(f0) |+| Kleisli(f1); f(0) = Some(0) 而不是 None。无论如何感谢您的回答。
    猜你喜欢
    • 2015-09-30
    • 1970-01-01
    • 2019-06-24
    • 1970-01-01
    • 1970-01-01
    • 2019-07-10
    • 2018-01-11
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多