使用 for-comprehension 的函数组合导致 Char 而不是 String

Functional composition using for-comprehension results in Char instead of String

我试图使用 for comprehension 来构造我的对象调用,这是我的简单实现:

object FuncA extends (String => Int => String) {
    override def apply(str: String): Int => String = i => {
      s"${(str.toInt + i).toString}"
    }
  }

  object FuncB extends (String => Int) {
    override def apply(str: String): Int = {
      str.toInt
    }
  }

  for {
    funcAStr <- FuncA("1")(1)
    funcBStr <- FuncB(funcAStr) // Fails here
  } yield {
    println(s"Final String incremented as int is $funcBStr")
  }

但奇怪的是,我遇到了一个问题,即 funcAStr 被解释为 Char 而不是 String。任何理想这是为什么?

像这样使用 andThen 尝试功能组合

(FuncA("1") andThen FuncB)(1)

输出

res0: Int = 2

尽管包含 for-loop 标记,但 Scala 中的 for 并未定义循环。 for 是定义 mapflatMapwithFilter 调用序列的 shorthand 方式。

您的代码转换为:

FuncA("1")(1).flatMap{ funcAStr =>
  FuncB(funcAStr).map{ funcBStr =>
    println(s"Final String incremented as int is $funcBStr")
  }
}   

Func("1")(1)returnsStringString 上的 flatMap 方法依次获取字符串的每个字符,因此 funcAStr 实际上是 Char 而不是 String.

在 Scala 中,for-comprehension 只是 flatMapmapforeach 嵌套调用的语法糖。简化一下,基本规则是每个箭头都将转换为嵌套的 flatMap,最后一个箭头将转换为 mapforeach,具体取决于您是否使用 yield

在你的情况下 for-comprehension 将转化为类似于:

val r: Seq[Unit] = 
    FuncA("1")(1).flatMap{ funcAStr : Char =>
       FuncB(funcAStr).map{ funcBStr: Int =>
           println(s"Final String incremented as int is $funcBStr")
       }
    }

这并没有多大意义,因为首先 funcBStr 期望 String 而不是 Char。但即使你修复了它,编译器也会抱怨,因为 flatMap 会期望可以表示为 GenTraversableOnce[B].

的东西

所以我猜你根本不应该在你的用例中使用 for-comprehension

如果您使用的是 IntelliJ,则可以使用快捷键 Ctrl+Alt+D,这将显示 Desugar Scala Code 对话框。然后,您将能够 select 展开理解 并向您展示如何将 理解 转化为 flatMap /map 调用。