2010-11-25 17 views
27

機能コードのデバッグは、必須コードのデバッグよりもはるかに扱いにくいものです。議論here,hereおよびhereを参照してください。 "Functional"デバッグは、関数/クロージャ/モナドの戻り値を検査することをサポートすべきです。デバッガ/ IDEには中間の戻り値を検査する機能がありますか?Scalaの機能コードのデバッグ

例えば、Scalaでこの行をデバッグする、私はr

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

Related-ish:http://stackoverflow.com/questions/268048/can-i-find-out-the-return-value-before-returning-while-debugging-in-visual-studio – Brian

+0

アップデート:There ScalaのEclipseデバッガの設計上の問題を説明する、scala internalsメーリングリストの新しいスレッドです。この質問に非常に関連しています。 http://thread.gmane.org/gmane.comp.lang.scala.internals/4130 – Adrian

答えて

30

私は、この問題をより管理しやすいチャンクに分解するためのアドバイスが最善の策だと思います。より小さな表現をデバッグするための1つのトリックは、hereのようにRubyのタップ関数を盗むことです。

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

これは、プリントアウトします:

をこれまでのところのように、いくつかのデバッグ値をプリントアウトし、おそらくあなたは、このようなチェーンの途中で表現を固執することを可能にする「をタップ」、および:一覧(2、4、6)
一覧(4、8、12)

それはたまにで私を助けます。

+0

+1のヒント! – fedesilva

+1

+1。これはKestrelコンビネータと呼ばれています。 – missingfaktor

+6

@missingfaktor:正式には、それはKコンビネータの一種です。鳥を使った組み合わせ論理を説明しているRaymond Smullyanの* To Mock A Mockingbird *という非常に有名な数学の本があります。この本は実際にKコンビネータを表すためにKestrelを使用しています。要するに:はい。 –

4

を戻す前に4つの関数呼び出しをステップし、各ステップでの戻り値を検査することができなければならない私が簡潔であることは非常にいいです知っています、これらの状況では、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) 

は/困難面倒ですが、それはあなたが愚かなバグを識別するのに役立ちん;:私の個人的なスタイルで、私はあなたの例を実装しているだろう何が起こっているのかを他の人が理解できるようにすることができます間違いなくデバッグに役立ちます。

+1

このコードは、中間値を持たないものよりもはるかに理解しがたいです。 – gerferra

+4

私はこれを理解することがより困難であることに同意します。 Scalaの構文に精通すれば、「one-liners」を理解しやすくなります。しかし、私の例では、IDE /デバッガの機能を提案しています。デバッガが実行されている間、一時的に "one-liners"をサンプルのようなものに展開するオプションがあればどうでしょうか?このようにして、コードにステップインして、中間関数の戻り値を調べることができます。デバッガがセッションを終了すると、コードは元のバージョンに戻ります。 – Adrian

+0

私はこのプログラミングのトレードオフを嫌い:) –

3

この問題に対する私のアプローチは、表現をREPLのvalにバインドする部分に分解することです。私が満足すると、私がREPLで行ったのと同じことをするテストケースを書くこともできます。そうすれば、物事は私が望むように残り、私や他の人が後で戻ってより明示的なバージョンを見ることができます。

使い勝手の良いテスト用ツールキットと組み合わせることで、レプリケート機能を使用できるようになったため、デバッガは私にとっては時代遅れです。

もちろんYMMV。

9

純粋に機能的な設定では、ステップスルーはあなたが考えるほど有用ではありません。すべてが純粋な関数で構成されているため、削除のプロセスを使って個々の要素を個別にテストできます。レイジーな評価設定では、コードをステップ実行することはあまり有用ではありません。

たとえば、Haskellのプログラムをデバッグすることは、関数呼び出しのトレースにはまったく関心がありません。あなたが興味を持っているのは、あなたの表現の漸進的な評価の痕跡です。これはScalaでの非常に便利な機能です。

+4

あなたの意見をよく理解していません。 「式の段階的評価」は「中間関数の戻り値の検査」と同じですか? – Adrian

+2

ええ、伝統的なIDEデバッグツールはまったく役に立たないと指摘しておきます。 – Apocalisp

2

あなた自身のコードをデバッグしようとすると、それは便利ですが、デバッグScalaのLANGまたは他のlibsの中には、コードを変更することはできません:(

1

IDEを持っていない場合、あなたはまだこのツールIを使用することができます書いた:

https://github.com/JohnReedLOL/scala-trace-debug

が仲介値を印刷するには、あなたがこの例でとることができます。

val result=(lists.filter(_>1).sort(_<_).zipWithIndex).filter{v=>(v._2)%2==0}.map{_._1} 

をそして、それにトレースを追加します:

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

暗黙の変換により、印刷することができます。

関連する問題