Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala Cats Writer向量为空_Scala_Scala Cats - Fatal编程技术网

Scala Cats Writer向量为空

Scala Cats Writer向量为空,scala,scala-cats,Scala,Scala Cats,我写这个简单的程序是为了学习Cats Writer是如何工作的 import cats.data.Writer import cats.syntax.applicative._ import cats.syntax.writer._ import cats.instances.vector._ object WriterTest extends App { type Logged2[A] = Writer[Vector[String], A] Vector("started the

我写这个简单的程序是为了学习Cats Writer是如何工作的

import cats.data.Writer
import cats.syntax.applicative._
import cats.syntax.writer._
import cats.instances.vector._

object WriterTest extends App {
   type Logged2[A] = Writer[Vector[String], A]
   Vector("started the program").tell
   val output1 = calculate1(10)
   val foo = new Foo()
   val output2 = foo.calculate2(20)
   val (log, sum) = (output1 + output2).pure[Logged2].run
   println(log)
   println(sum)

   def calculate1(x : Int) : Int = {
      Vector("came inside calculate1").tell
      val output = 10 + x
      Vector(s"Calculated value ${output}").tell
      output
   }
}

class Foo {
   def calculate2(x: Int) : Int = {
      Vector("came inside calculate 2").tell
      val output = 10 + x
      Vector(s"calculated ${output}").tell
      output
   }
}
程序运行正常,输出正常

> run-main WriterTest
[info] Compiling 1 Scala source to /Users/Cats/target/scala-2.11/classes...
[info] Running WriterTest 
Vector()
50
[success] Total time: 1 s, completed Jan 21, 2017 8:14:19 AM

但为什么向量是空的?它不应该包含我使用“tell”方法的所有字符串吗?

示例代码的问题是您没有使用
tell方法的结果

如果你看一下它的签名,你会看到:

final class WriterIdSyntax[A](val a: A) extends AnyVal {

   def tell: Writer[A, Unit] = Writer(a, ())

}
很明显,
tell
返回一个
Writer[a,Unit]
结果,该结果立即被丢弃,因为您没有将其赋值

使用
Writer
(以及Scala中的任何monad)的正确方法是通过其
flatMap
方法。它看起来与此类似:

println(
  Vector("started the program").tell.flatMap { _ =>
    15.pure[Logged2].flatMap { i =>
      Writer(Vector("ended program"), i)
    }
  }
)
执行上述代码时,您将看到:

WriterT((Vector(started the program, ended program),15))
如您所见,消息和int都存储在结果中

现在这有点难看,Scala实际上提供了一种更好的方法:用于理解。对于理解来说,有一点语法上的糖分,允许我们以这种方式编写相同的代码:

println(
  for {
    _ <- Vector("started the program").tell
    i <- 15.pure[Logged2]
    _ <- Vector("ended program").tell
  } yield i
)
println(
为了{

_当您在
向量上调用
时,每次创建
编写器[Vector[String],Unit]
。然而,实际上,你从来没有对你的
编写器做过任何事情,你只是丢弃了它们。此外,你调用
pure
来创建你的最终
编写器
,它只会创建一个带有空
向量的
编写器
。你必须将编写器组合在一个链中,该链承载你的价值和信息圆形

type Logged[A] = Writer[Vector[String], A]

val (log, sum) = (for {
  _ <- Vector("started the program").tell
  output1 <- calculate1(10)
  foo = new Foo()
  output2 <- foo.calculate2(20)
} yield output1 + output2).run

def calculate1(x: Int): Logged[Int] = for {
  _ <- Vector("came inside calculate1").tell
  output = 10 + x
  _ <- Vector(s"Calculated value ${output}").tell
} yield output

class Foo {
  def calculate2(x: Int): Logged[Int] = for {
    _ <- Vector("came inside calculate2").tell
    output = 10 + x
    _ <- Vector(s"calculated ${output}").tell
  } yield output
}
flatMap
是一元绑定操作,这意味着它知道如何获取两个一元值(在本例中为
Writer
)并将它们连接在一起以获得一个新值。在本例中,它生成一个
Writer
,其中包含日志和右侧一个值的串联

注意没有副作用。
Writer
没有全局状态可以记住所有对
tell
的调用。相反,您可以创建许多
Writer
并将它们与
flatMap
连接在一起,最后得到一个大的

def calculate1(x: Int): Logged[Int] = Vector("came inside calculate1").tell.flatMap { _ =>
  val output = 10 + x
  Vector(s"calculated ${output}").tell.map { _ => output }
}