如何在Scala中跟踪函数求值?

如何在Scala中跟踪函数求值?,scala,functional-programming,trace,Scala,Functional Programming,Trace,我正在学习Scala中的函数编程,为了更好地理解函数的工作原理,我经常需要跟踪函数求值 例如,具有以下功能: def foldRight[A,B](l: List[A], z: B)(f: (A, B) => B): B = l match { case Nil => z case Cons(x, xs) => f(x, foldRight(xs, z)(f)) } 以下电话: foldRight(Cons(1, Cons(2, Cons(3, Nil

我正在学习Scala中的函数编程,为了更好地理解函数的工作原理,我经常需要跟踪函数求值

例如,具有以下功能:

def foldRight[A,B](l: List[A], z: B)(f: (A, B) => B): B =
  l match {
    case Nil => z
    case Cons(x, xs) => f(x, foldRight(xs, z)(f))
  }
以下电话:

foldRight(Cons(1, Cons(2, Cons(3, Nil))), 0)(_ + _)
我想打印它的评估跟踪,如下所示:

foldRight(Cons(1, Cons(2, Cons(3, Nil))), 0)(_ + _)
1 + foldRight(Cons(2, Cons(3, Nil)), 0)(_ + _)
1 + (2 + foldRight(Cons(3, Nil), 0)(_ + _))
1 + (2 + (3 + (foldRight(Nil, 0)(_ + _))))
1 + (2 + (3 + (0)))
6

目前,我正在做手动或注射丑陋的打印的。我如何以一种方便优雅的方式实现这一点

我假设Cons和::是相同的操作。 如果您不介意只获取当前元素和累加器,可以执行以下操作:

def printable(x:Int, y:Int): Int = {
    println("Curr: "+x.toString+" Acc:"+ y.toString)
    x+y
} 
foldRight(List(1, 2, 3, 4), 0)(printable(_,_))  
//> Curr: 4 Acc:0
//| Curr: 3 Acc:4
//| Curr: 2 Acc:7
//| Curr: 1 Acc:9
//| res0: Int = 10
如果您想要整个“堆栈跟踪”,这将为您提供您要求的输出,尽管它远不是优雅的:

def foldRight[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
  var acc = if (l.isEmpty) "" else l.head.toString
  def newAcc(acc: String, x: A) = acc + " + (" + x
  def rightSide(xs: List[A], z: B, size: Int) = xs.toString + "," + z + ")" * (l.size - size + 1)
  def printDebug(left: String, right: String) = println(left + " + foldRight(" + right)

  def go(la: List[A], z: B)(f: (A, B) => B): B = la match {
    case Nil => z
    case x :: xs => {
      acc = newAcc(acc, x)
      printDebug(acc, rightSide(xs, z, la.size))
      f(x, go(xs, z)(f))
    }
  }
  if (l.isEmpty) z
  else f(l.head, go(l.tail, z)(f))
}
注意:要去除变量“acc”,可以在“go”函数中设置第二个累加器


这个函数也会返回您要求的输出,但不会模糊foldRight

class Trace[A](z: A) {
  var list = List[A]()
  def store(x: A) = {
    list = list :+ x
  }

  def getTrace(level: Int): String = {
    val left = list.take(level).map(x => s"$x + (").mkString
    val right = list.drop(level).map(x => s"$x,").mkString
    if (right.isEmpty)
      s"${left.dropRight(4)}" + ")" * (list.size - 1)
    else
      s"${left}foldRight(List(${right.init}), $z)" + ")" * (list.size - level - 1)
  }

  def getFullTrace: String =
    { for (i <- 0 to list.size) yield getTrace(i) }.mkString("\n")

  def foldRight(l: List[A], z: A)(f: (A, A) => A): A = l match {
    case Nil => z
    case x :: xs => store(x); f(x, foldRight(xs, z)(f))
  }
}

val start = 0
val t = new Trace[Int](start)
t.foldRight(List(1, 2, 3, 4), start)(_ + _) 
t.getFullTrace 
类跟踪[A](z:A){
变量列表=列表[A]()
def存储(x:A)={
列表=列表:+x
}
def getTrace(级别:Int):字符串={
val left=list.take(level.map)(x=>s“$x+(“”).mkString
val right=list.drop(level).map(x=>s“$x,”).mkString
如果(对,我是空的)
s“${left.dropRight(4)}”+”*(list.size-1)
其他的
s“${left}foldRight(List(${right.init}),$z)”+”*(List.size-level-1)
}
def getFullTrace:字符串=
{for(ia):A=l匹配{
案例Nil=>z
案例x::xs=>store(x);f(x,foldRight(xs,z)(f))
}
}
val start=0
val t=新跟踪[Int](开始)
t、 foldRight(列表(1,2,3,4),start)(uu+uu)
t、 getFullTrace

谢谢@goozez,这是我想要的,尽管我想知道是否有一种更通用的解决方案可以应用于任何函数,而不必编写如此繁琐的代码。@Rafa:我一直在思考如何在不模糊f和foldRight的情况下做到这一点。也许这一个更符合你的喜好。我已经编辑了我的答案。干杯