简体   繁体   中英

What is the purpose of *> and <* in Scalaz

Let's take a look at the implementation of finish on a Scalaz Task

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)
    })

What is the *> accomplishing here?

This is the Apply syntax. I recently added some examples of using the apply syntax to the examples sub-project of scalaz, you can see specifically some discussion of *> and <* here:

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

The idea is that you are evaluating two 'effectful' computations on either side of the combinator, using the Apply instance to combine the effects, but throwing away one of the resulting values. <* throws away the value on the right, and *> throws away the value on the left.

In your example, we are using Apply[Future] to combine the effects, and the effect is the delayed computation of the future. In the first case match we have this one:

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

So f(Some(e)).get returning the Future[Unit] that the Task is wrapping when we apply the f function, this Task is just being run for its side effects. The right half of the apply Future.now(-\\/(e)) is the value we want to return, in a Future , but we want this future to deppend on the result of the side effecting Future[Unit] . The result is that we get a Future[-\\/] , but it is one that won't be complete until the side effect has completed.

I find that a good example of where these combinators are easy to understand are parser combinators. Let's assume we have some parser:

trait Parser[A]

Which is something that will consume some input and produce an A in the process. Say we have a method which will parse a character:

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

and some method which will parse some arbitrary string:

def foo: Parser[String]

then we can make a parser for our arbitrary string inside parentheses:

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

this creates a parser that although it will consume an open parenthesis, then a foo, then a close parenthesis, it will only return the result of parsing the foo. We don't care about actually receiving the output of the chr('(') and chr(')') parers, but we want their effects of consuming input to still be combined into the resulting parser.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM