将一系列地图操作转换为for-comprehension

时间:2011-07-30 00:25:19

标签: scala functional-programming for-comprehension

我在Scala编程第23.5节中读到,map,flatMap和filter操作总是可以转换为for-comprehensions,反之亦然。

我们给出了以下等价物:

def map[A, B](xs: List[A], f: A => B): List[B] =
  for (x <- xs) yield f(x)

我有一系列地图操作计算的值:

val r = (1 to 100).map{ i => (1 to 100).map{i % _ == 0} }
                  .map{ _.foldLeft(false)(_^_) }
                  .map{ case true => "open"; case _ => "closed" }

我想知道这会是什么样的理解。我该如何翻译?

(如果它有用,用语言表示:

  • 取整数从1到100
  • 为每个,创建一个包含100个布尔值的列表
  • 使用XOR运算符折叠每个列表,返回布尔值
  • 根据布尔值
  • 生成100个字符串“open”或“closed”的列表

我想有一种标准的方法来翻译地图操作,其中的实际功能的细节并不重要。我可能错了。)

1 个答案:

答案 0 :(得分:6)

这是您正在寻找的那种翻译吗?

for (i <- 1 to 100;
     val x = (1 to 100).map(i % _ == 0);
     val y = x.foldLeft(false)(_^_);
     val z = y match { case true => "open"; case _ => "closed" })
  yield z

如果需要,map定义中的x也可以翻译为“内部”理解。

回想起来,一系列链式map调用有点微不足道,因为你可以用组合函数等效地调用map一次:

 s.map(f).map(g).map(h) == s.map(f andThen g andThen h)

flatMapfilter参与时,我发现for-comprehension是一个更大的胜利。考虑

for (i <- 1 to 3;
     j <- 1 to 3 if (i + j) % 2 == 0;
     k <- 1 to 3) yield i ^ j ^ k

(1 to 3).flatMap { i =>
  (1 to 3).filter(j => (i + j) % 2 == 0).flatMap { j =>
    (1 to 3).map { k => i ^ j ^ k }
  }
}