在 Scala 中调试功能代码
调试函数式代码肯定比调试命令式代码更棘手。请参阅此处的讨论、此处和此处。 “函数式”调试应该支持检查函数/闭包/monad 的返回值。是否有任何调试器/IDE 具有(计划具有)检查中间返回值的能力?
例如,要在 Scala 中调试这一行,我应该能够单步执行 4 个函数调用,并在返回 r
之前检查每一步的返回值
val r=(ls filter (_>1) sort (_<_) zipWithIndex) filter {v=>(v._2)%2==0} map{_._1}
Debugging functional code is definitely more tricky than debugging imperative code. See discussions here, here and here. "Functional" debugging should support inspecting the return value of functions/closures/monads. Do any debuggers/IDEs have (plan to have) the ability to inspect intermediate return values?
For example, to debug this line in Scala, I should be able to step through 4 function invocations and inspect the returned value at each step before returning r
val r=(ls filter (_>1) sort (_<_) zipWithIndex) filter {v=>(v._2)%2==0} map{_._1}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我认为每个人的建议是将其分解为更易于管理的部分是最好的方法。调试较小表达式的一个技巧是窃取 Ruby 的 tap 函数,如 此处。 “tap”允许您将表达式粘贴在链的中间,如下所示,并且可能打印出一些调试值,如下所示:
这将打印出:
它偶尔对我有帮助。
I think everybody's advice to break this thing down to more manageable chunks is the best approach. One trick for debugging smaller expressions is to steal Ruby's tap function, as described here. "tap" allows you to stick an expression in the middle of a chain like this, and perhaps print out some debug values, like so:
This will print out:
It helps me every once in a while.
在纯粹的功能设置中,单步执行并不像您想象的那么有用。由于一切都是由纯函数组成,因此您可以使用消除过程单独测试这些部分。在惰性评估设置中,单步执行代码的用处甚至更少。
例如,在 Haskell 中调试程序时,您根本不会对跟踪函数调用感兴趣。您感兴趣的是中间函数返回值的痕迹。对于任何函数式语言来说,能够为任何表达式提供这样的跟踪都是一个非常有用的功能。
In a purely functional setting, stepping through is not nearly as useful as you might think. Since everything is composed of pure functions, you can just test those pieces individually using a process of elimination. In a lazy evaluation setting, stepping through code is even less useful.
Debugging programs in Haskell, for example, you would not at all be interested in tracing function calls. What you are interested in is a trace of intermediate function return values. It would be a very useful feature in any functional language to be able to give such a trace for any expression.
我知道简洁非常好,并且我同意您的观点,即 IDE 应该有助于在这些情况下进行调试。但目前我已经改变了我的编码风格以协助调试。以我个人的风格,我会将您的示例实现为:
想出有意义的名称很困难/费力,但它确实可以帮助您识别愚蠢的错误;可以帮助其他人了解正在发生的事情;并且绝对有助于调试。
I know being concise is very nice, and I agree with you that IDEs should help with the debugging in these situations. But for the time being I have changed my coding style to assist with debugging. In my personal style I would have implemented your example as:
Coming up with meaningful names is difficult/laborious, but it does help you identify silly bugs; may help others to understand what is going on; and definitely helps with debugging.
我解决这个问题的方法是将表达式分解为将结果绑定到 REPL 中的值的部分。当我满意时,我什至可以编写一个测试用例,其功能与我在 REPL 中所做的相同,这样我确信事情保持我想要的样子,这样我或其他人可以稍后回来看到更明确的版本。
使用 repl 进行探索的能力加上漂亮且易于使用的测试工具包使得调试器对我来说几乎已经过时了。
当然YMMV。
My approach to this problem is to break the expression down into parts binding the results to vals in the REPL. When I am satisfied I may even write a test case that does the same I did in the REPL so that I am sure things stay as I want and so that I or somebody else can come back later and see a more explicit version.
The ability to use the repl to explore coupled with nice and easy to use testing toolkits has made debuggers all but obsolete for me.
Of course YMMV.
从 Scala 2.13 开始,链接操作
点击
,如 Adam Rabung 的答案,已包含在标准库中,可以通过打印管道的中间版本来进行调试:tap< /code>
链接操作在返回原始值时对值(在本例中为
List
)施加副作用(在本例中为println
):Starting
Scala 2.13
, the chaining operationtap
, as mentioned in Adam Rabung's answer, has been included in the standard library, and can be used for debugging by printing intermediate versions of a pipeline:The
tap
chaining operation applies a side effect (in this caseprintln
) on a value (in this case aList
) while returning the original value:如果你没有IDE,你仍然可以使用我写的这个工具:
https://github .com/JohnReedLOL/scala-trace-debug
要打印中间值,您可以采用以下示例:
并向其添加跟踪:
隐式转换允许您打印。
If you don't have an IDE, you can still use this tool I wrote:
https://github.com/JohnReedLOL/scala-trace-debug
To print the intermediary values, you can take this example:
And add traces to it:
An implicit conversion allows you to print.