print中的scala for-comprehension

use*_*own 29 scala variable-assignment println for-comprehension

为了理解,我不能只是提出一个印刷声明:

def prod (m: Int) = {
  for (a <- 2 to m/(2*3);
    print (a + "  ");
    b <- (a+1) to m/a;
    c = (a*b) 
    if (c < m)) yield c
}
Run Code Online (Sandbox Code Playgroud)

但我可以通过虚拟任务轻松绕过它:

def prod (m: Int) = {
  for (a <- 2 to m/(2*3);
    dummy = print (a + "  ");
    b <- (a+1) to m/a;
    c = (a*b) 
    if (c < m)) yield c
}
Run Code Online (Sandbox Code Playgroud)

作为副作用,并且仅在开发中的代码中使用(到目前为止),是否有更好的临时解决方案?

是否有一个严重的问题为什么我不应该使用它,除了副作用?

更新显示真实代码,其中调整一个解决方案比预期更难:

从与Rex Kerr的讨论来看,必要性已经上升到显示原始代码,这有点复杂,但似乎与问题无关(2x .filter,最后调用方法),但是当我试图将Rex'模式应用到它我失败了,所以我在这里发布:

  def prod (p: Array[Boolean], max: Int) = {
    for (a <- (2 to max/(2*3)).
        filter (p);
      dummy = print (a + "  ");
      b <- (((a+1) to max/a).
         filter (p));
      if (a*b <= max)) 
        yield (em (a, b, max)) }
Run Code Online (Sandbox Code Playgroud)

这是我的尝试 - (b*a).filter是错误的,因为结果是一个int,而不是一个可过滤的int集合:

  // wrong: 
  def prod (p: Array[Boolean], max: Int) = {
    (2 to max/(2*3)).filter (p).flatMap { a =>
      print (a + " ")
      ((a+1) to max/a).filter (p). map { b => 
        (b * a).filter (_ <= max).map (em (a, b, max))
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

第二部分属于评论,但无法阅读,如果写在那里 - 也许我最后删除它.请包涵.

好的 - 这是Rex在代码布局中的最后答案:

  def prod (p: Array[Boolean], max: Int) = {
    (2 to max/(2*3)).filter (p).flatMap { a =>
      print (a + " ")
      ((a+1) to max/a).filter (b => p (b) 
        && b * a < max).map { b => (m (a, b, max))
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

mis*_*tor 42

这就是你需要写它的方式:

scala> def prod(m: Int) = {
     |   for {
     |     a <- 2 to m / (2 * 3)
     |     _ = print(a + " ")
     |     b <- (a + 1) to (m / a)
     |     c = a * b
     |     if c < m
     |   } yield c
     | }
prod: (m: Int)scala.collection.immutable.IndexedSeq[Int]

scala> prod(20)
2 3 res159: scala.collection.immutable.IndexedSeq[Int] = Vector(6, 8, 10, 12, 14
, 16, 18, 12, 15, 18)
Run Code Online (Sandbox Code Playgroud)

  • 老实说,我认为`dummy = print(a +"")`更清楚 - 如果这是唯一的改变.有人看着这一行,他们会立即知道它是一个用于打印的虚拟变量赋值.当使用下划线时,他们可能想知道它是否是他们之前从未见过的普遍下划线的新用法. (4认同)
  • 我发现`_`版本已清除。我想个人品味很重要。 (2认同)

Xav*_*hot 5

开始Scala 2.13,链接操作tap已包含在标准库中,并且可以在需要打印管道的某些中间状态的任何地方以最小的侵入性使用:

import util.chaining._

def prod(m: Int) =
  for {
    a <- 2 to m / (2 * 3)
    b <- (a + 1) to (m / a.tap(println)) // <- a.tap(println)
    c =  a * b
    if c < m
 } yield c

prod(20)
// 2
// 3
// res0: IndexedSeq[Int] = Vector(6, 8, 10, 12, 14, 16, 18, 12, 15, 18)
Run Code Online (Sandbox Code Playgroud)

tap链接操作适用的副作用(在这种情况下println上的值)(在这种情况下a),而在返回值(a)不变:

def tap[U](f: (A) => U): A


调试的时候很方便,tap不用修改代码就可以用一堆s:

def prod(m: Int) =
  for {
    a <- (2 to m.tap(println) / (2 * 3)).tap(println)
    b <- (a + 1) to (m / a.tap(println))
    c = (a * b).tap(println)
    if c < m
 } yield c
Run Code Online (Sandbox Code Playgroud)