Trivial Scala在地图功能之间“记录”

时间:2018-03-10 08:47:50

标签: scala

def foo(l: List[Int]) =
  List(1,2,3)
    .map(_ + 1)               // A
    .map(x => {println(x);x}) // B
    .map(_ + 2)               // C
    .map(x => {println(x);x}) // D
    .map(_ + 3)

目的是在步骤AC之后打印或登录文件,这是其中一个实现。这是一个好习惯吗?

或者将其分解为多个临时变量,

def foo(l: List[Int]) = {
  val nums = List(1,2,3).map(_ + 1)
  nums.foreach(println)
  val nums2 = nums.map(_ + 2)
  nums2.foreach(println)
  nums2.map(_ + 3)

}

有没有更好或更直接的方式?感谢

更新1

让我进一步澄清我的意图。我的想法是将副作用println(...)移出map(...)函数,但我想在此过程中打印结果。我认为不需要优化第B行和D

3 个答案:

答案 0 :(得分:1)

一种方法是创建一个继承自List类的类,并覆盖.map方法。

问题是List无法在密封时继承。

因此,解决方案是将列表包装在新类中并编写.map方法,该方法将调用原始List.map并打印每个映射元素的映射结果:

class PrintList[T](l: List[T]) {

  def map[B](f: T => B): PrintList[B] = {
    new PrintList[B](l.map { e =>
      val v = f(e); println(v); v
    })
  }

  def toList(): List[T] = l

  override def toString(): String = "Print" + l.toString
}

以这种方式应用:

new PrintList(List(1, 2, 3)).map(_ + 1).map(_ + 2)

打印:

2
3
4
4
5
6

并返回:

println(new PrintList(List(1, 2, 3)).map(_ + 1).map(_ + 2))
> PrintList(4, 5, 6)
println(new PrintList(List(1, 2, 3)).map(_ + 1).map(_ + 2).toList)
> List(4, 5, 6)

答案 1 :(得分:0)

也许你重构函数+记录到一个新函数:

def loggedFun (x: Int)(f: Int => Int) : Int = { val y = f(x); println (y); y }

可以像这样使用:

List(1,2,3).map(loggedFun (_)(_ + 1)).map(loggedFun (_)(_ + 2)).map(_ + 3)

并进一步推广出类型(Int→A)。

def loggedFun[A] (x: A)(f: A => A) : A = { val y = f(x); println (y); y }

我很确定,类别理论中有从A到A的这类函数的名称,但我不知道哪个;对不起。

答案 2 :(得分:0)

对这个微不足道的问题的非平凡回答是作家monad。这个模式的一个很好的例子是http://blog.tmorris.net/posts/the-writer-monad-using-scala-example/