Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Debugging 在Scala中调试函数代码_Debugging_Scala_Functional Programming - Fatal编程技术网

Debugging 在Scala中调试函数代码

Debugging 在Scala中调试函数代码,debugging,scala,functional-programming,Debugging,Scala,Functional Programming,调试函数式代码肯定比调试命令式代码更棘手。见讨论,和。“功能性”调试应支持检查函数/闭包/单子的返回值。是否有任何调试器/IDE(计划)能够检查中间返回值 例如,要在Scala中调试这一行,我应该能够分步执行4个函数调用,并在返回r val r=(ls filter (_>1) sort (_<_) zipWithIndex) filter {v=>(v._2)%2==0} map{_._1} val r=(ls-filter(>1)排序(v.(_2)%2==0}map{uu

调试函数式代码肯定比调试命令式代码更棘手。见讨论,和。“功能性”调试应支持检查函数/闭包/单子的返回值。是否有任何调试器/IDE(计划)能够检查中间返回值

例如,要在Scala中调试这一行,我应该能够分步执行4个函数调用,并在返回
r

val r=(ls filter (_>1) sort (_<_) zipWithIndex) filter {v=>(v._2)%2==0} map{_._1}
val r=(ls-filter(>1)排序(v.(_2)%2==0}map{uu._1}

我知道简洁非常好,我同意您的观点,IDE应该在这些情况下帮助调试。但目前我已经改变了我的编码风格以帮助调试。以我个人的风格,我会将您的示例实现为:

val noZeroLs = ls.filter(_>1)
val sortedLs = noZeroLs.sort(_<_)
val indexedNoZeroLs = sortedLs.zipWithIndex
val everySecondIndexedL = indexedNoZeroLs.filter(v => (v._2) % 2 == 0)
val everySecondL = everySecondIndexedL.map(_._1)
val noZeroLs=ls.filter(>1)
val sortedLs=noZeroLs.sort(v.2)%2==0)
val everySecondL=everySecondIndexedL.map(u._1)

提出有意义的名称是困难的/费力的,但它确实可以帮助您识别愚蠢的错误;可以帮助其他人理解正在发生的事情;并且肯定有助于调试。

我解决这个问题的方法是将表达式分解为多个部分,将结果绑定到REPL中的VAL。当我满意时,我甚至可以编写一个测试c如果这与我在REPL中所做的相同,那么我确信事情会保持我想要的状态,这样我或其他人可以稍后返回并看到更明确的版本

使用repl进行探索的能力,加上良好且易于使用的测试工具包,使得调试器对我来说几乎已经过时


当然是YMMV.

< P>我认为每个人建议把这个问题分解成更易于管理的块是最好的方法。调试小表达式的一个窍门是窃取露比的TAP函数,如“TAP”允许你把一个表达式粘贴在这样的一个链的中间,也许打印出一些调试值,比如:

val ls = List(1,2,3).map(_ * 2)
                .tap(soFar => println("So far: " + soFar))
                .map(_ * 2)
println(ls)
这将打印出:

到目前为止:列表(2、4、6)
名单(4、8、12)


偶尔它会对我有所帮助。

在纯函数设置中,单步执行并不像您想象的那样有用。因为所有内容都是由纯函数组成的,所以您可以使用消除过程单独测试这些部分。在惰性评估设置中,单步执行代码更不有用


例如,在Haskell中调试程序时,您根本不会对跟踪函数调用感兴趣。您感兴趣的是对中间函数返回值的跟踪。在任何函数语言中,能够对任何表达式进行这样的跟踪都是非常有用的功能。

当您尝试调试自己的函数时,这是非常有用的n代码,但在调试scala lang或其他LIB时,您不能更改代码:(

如果您没有IDE,您仍然可以使用我编写的工具:

要打印中间值,可以采用以下示例:

val result=(lists.filter(_>1).sort(_<_).zipWithIndex).filter{v=>(v._2)%2==0}.map{_._1}
val result=(lists.filter(>1).sort(v.(_2)%2==0}.map{uu._1}
并向其添加跟踪:

import scala.trace.implicitlyTraceable
val result=(lists.filter(_>1).out.sort(_<_).println.zipWithIndex).filter{v=>(v._2)%2==0}.out.map{_._1}.out
导入scala.trace.implicitlyTraceable
val result=(lists.filter(>1).out.sort(v.2)%2==0}.out.map{uu.1}.out

隐式转换允许您打印。

Scala 2.13
开始,中提到的链接操作已包含在标准库中,并可通过打印管道的中间版本用于调试:

import scala.util.chaining._

scala> val ls = List(1,2,3).map(_ * 2).tap(println).map(_ * 2).tap(println)
List(2, 4, 6)
List(4, 8, 12)
ls: List[Int] = List(4, 8, 12)

链接操作在返回原始值的同时,对值(在本例中为列表)应用副作用(在本例中为
println
):

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


相关ish:更新:scala Internal邮件列表上有一个新线程,讨论scala Eclipse调试器的设计问题。与此问题非常相关。此代码更难理解,没有中间值的代码,有更多的东西需要跟踪……我同意这更难理解一旦你熟悉了Scala语法,“一行程序”就更容易理解了。但是你的例子让我为IDE/调试器推荐了一个特性:如果我有一个临时扩展“一行程序”的选项怎么办当调试器运行时,我可以进入到类似您的示例中。这样我就可以进入代码并检查中间函数返回值。一旦调试器完成会话,代码将还原到我的原始版本。该死的,我讨厌这种编程权衡:)我不确定我是否理解您的观点。不是吗“表达式的逐步求值”与“检查中间函数返回值”相同?是的,我并不反对你,只是指出传统的IDE调试工具是完全无用的。@missingfaktor:正式地说,它是(的变体)K组合器。Raymond Smullyan有一本非常著名的数学书叫做《模仿一只知更鸟》,它用鸟来解释组合逻辑,这本书确实用红隼来表示K组合器,这个术语甚至已经扩展到了书之外。简言之:是的。这里的一个问题是Java的调试元数据格式s
.class
文件根本无法以小于一行的粒度记录调试元数据。对于这样的功能代码(即使在Java(!)中),您需要一种以(子-)表示调试元数据的方法表达式级别。因此,基本上,您必须使用
tap
进行
printf
调试,重新格式化为多行,并(暂时)将子表达式分解为
val
s。返回到使用println的cave调试?哦,天哪。