scala - 推断类型以供理解

标签 scala scalaz

设置:

import scalaz._; import Scalaz._

case class Foo(map: Map[Int, String] = Map.empty, set: Set[Int] = Set.empty)

val `foo.map`: Lens[Foo, Map[Int, String]] = Lens.lensu((f, m) => f.copy(map = m), _.map)
val `foo.set`: Lens[Foo, Set[Int]] = Lens.lensu((f, s) => f.copy(set = s), _.set)

case class Bar(cond: Boolean)

val listOfBars = List(Bar(true), Bar(false))

现在这不编译

listOfBars.runTraverseS[Foo, Unit](Foo()) { bar =>
  if (bar.cond)
    `foo.map` += 1 -> "a"
  else
    `foo.set` += 2
}

这个问题是 Lens[Foo, Map[K, V]].+= 返回一个 State[Foo, Map[K, V]]Lens[Foo, Set[A]].+= 返回一个 State[Foo, Set[A]]。回想一下,State[S, A]A

中是不变的

然而,这确实编译:

listOfBars.runTraverseS[Foo, Unit](Foo()) { bar =>
  for {
    _ <- State.init[Foo]
    x <- {

         if (bar.cond)
           `foo.map` += 1 -> "a"
         else
           `foo.set` += 2

    }
  } yield ()
}
  1. 为什么会编译?
  2. x 的类型是什么? (IDEA 说它是 type $_1 或类似的东西 - 我假设它不是可表示的类型)

编辑

如果我将 yield () 更改为 yield println(x) 并打印 for comprehension 的输出,我会得到:

Map(1 -> a)
Set(2)
(Foo(Map(1 -> a),Set(2)),List((), ()))

最佳答案

问题是if表达式的类型

if (bar.cond)
  `foo.map` += 1 -> "a"
else
  `foo.set` += 2 

State[Foo, Serializable]或类似的(scala可以统一MapSet类型的通用基类型);但是 runTraverseS[Foo, Unit] 需要一个 State[Foo, Unit](因为声明了 Unit),这些类型不能统一。

解决方案很简单,只需映射结果并像这样“作废”它:

val unit = ()

listOfBars.runTraverseS[Foo, Unit](Foo()) { bar =>
  (if (bar.cond)
    `foo.map` += 1 -> "a"
  else
    `foo.set` += 2
  ).map(Function.const(unit))
}

这实际上是代码的“for”版本所做的(它只是丢弃值 x,其类型类似于 State[Foo, Serializable]

关于scala - 推断类型以供理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47288392/

相关文章:

validation - Scala中的错误处理单子(monad)?尝试与验证

scala - 如果列表不为空,scala 或 scalaz 中是否有函数可以将函数应用于列表?

scala - 函数式编程中 Store Comonad 和可表示 Store Comonad 之间有什么区别?

java - HPROF结果解释

scala - java.lang.ClassNotFoundException : play. core.server.NettyServer 当更多 Play 库添加到 build.sbt 时

scala - 在 Play 中使用 "implicit request"是什么意思?

scala - Scalamock无法区分 future

scalaz - Scalaz http 模块发生了什么?

scala - 使用 scalaz 的开源项目示例

java - 如何在 IntelliJ Idea 中禁用 Gradle 守护程序?