*>的目的是什么?和Scalaz中的< *

时间:2014-09-17 22:37:24

标签: scala functional-programming scalaz applicative

让我们看一下Scalaz任务的完成实现

def onFinish(f: Option[Throwable] => Task[Unit]): Task[A] =
    new Task(get flatMap {
        case -\/(e) => f(Some(e)).get *> Future.now(-\/(e))
        case r => f(None).get *> Future.now(r)
    })

什么是*>在这里完成了吗?

1 个答案:

答案 0 :(得分:6)

这是Apply语法。我最近添加了一些使用apply语法到scalaz的examples子项目的示例,你可以在这里特别看到*><*的一些讨论:

https://github.com/scalaz/scalaz/blob/series/7.2.x/example/src/main/scala/scalaz/example/ApplyUsage.scala#L94-L130

这个想法是你正在评估组合器两侧的两个“有效”计算,使用Apply实例来组合效果,但丢弃其中一个结果值。 <*会抛弃右侧的值,*>会抛弃左侧的值。

在您的示例中,我们使用Apply [Future]来组合效果,效果是延迟计算未来。在第一个案例匹配中我们有这个:

 f(Some(e)).get *> Future.now(-\/(e))

因此f(Some(e)).get在我们应用Future[Unit]函数时返回Task正在包装的f,此任务正在运行其副作用。应用Future.now(-\/(e))的右半部分是我们想要返回的值Future,但我们希望这个未来能够对副作用Future[Unit]的结果产生影响。结果是我们得到Future[-\/],但是在副作用完成之前它是不完整的。

我发现这些组合器易于理解的一个很好的例子是解析器组合器。我们假设我们有一些解析器:

trait Parser[A]

这会消耗一些输入并在过程中产生A。假设我们有一个解析角色的方法:

def chr(c: Char): Parser[Char]

和一些解析一些任意字符串的方法:

def foo: Parser[String]

然后我们可以为括号内的任意字符串创建一个解析器:

val parentheticalFoo: Parser[String] = chr('(') *> foo <* chr(')')

这会创建一个解析器,虽然它会使用一个开括号,然后是一个foo,然后是一个闭括号,它只会返回解析foo的结果。我们并不关心实际接收chr('(')chr(')') parers的输出,但我们希望它们消耗输入的效果仍然可以合并到生成的解析器中。