ocamlをターミナルから実行するにあたり、例えば、リストを反転させるといった再帰関数などで関数の呼び出し毎にどのようにリストが変化していくのかを見たいのですが、それを見る方法はありますか?
よろしくお願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
#trace
ディレクティブを使うと指定した関数に対する入力(引数)と出力(戻り値)を表示できます。
たとえば、上のチュートリアルの例を拝借すると、以下のように使えます。
ocaml
1# (* fib関数を定義する *);; 2# let rec fib x = if x <= 1 then 1 else fib (x - 1) + fib (x - 2);; 3val fib : int -> int = <fun> 4 5# (* fib関数に対するトレースをオンにする *) 6# #trace fib;; 7fib is now traced. 8 9# (* fib関数を適用する *) 10# fib 3;; 11fib <-- 3 12fib <-- 1 13fib --> 1 14fib <-- 2 15fib <-- 0 16fib --> 1 17fib <-- 1 18fib --> 1 19fib --> 2 20fib --> 3 21- : int = 3 22 23# (* fib関数に対するトレースをオフにする *) 24# #untrace fib;; 25fib is no longer traced.
fib <-- 3
が入力で、fib --> 1
が出力です。
この#trace
はリストを反転させるような関数でももちろん使えますが、そのままだと多分うまくいきません。チュートリアルにも書かれているように、多相な関数(Polymorphic function)に対してトレースを使った場合、多相な値が<poly>
のように表示されてしまい、実際の値を見ることができません。
たとえばリストを反転させるrev
関数を以下のように定義したとします。
ocaml
1# let rec revAppend l1 l2 = 2 match l1 with 3 [] -> l2 4 | v :: l1' -> revAppend l1' (v :: l2);; 5val revAppend : 'a list -> 'a list -> 'a list = <fun> 6 7# let rev l = revAppend l [];; 8val rev : 'a list -> 'a list = <fun>
注:この定義は書籍『プログラミング in Ocaml』(五十嵐淳 著、技術評論社)から拝借しました。
これに対して#trace
をかけても有益な情報は得られません。
ocaml
1# #trace revAppend;; 2revAppend is now traced. 3 4# rev [1; 2; 3];; 5revAppend <-- [<poly>; <poly>; <poly>] 6revAppend --> <fun> 7revAppend* <-- [] 8revAppend <-- [<poly>; <poly>] 9revAppend --> <fun> 10revAppend* <-- [<poly>] 11revAppend <-- [<poly>] 12revAppend --> <fun> 13revAppend* <-- [<poly>; <poly>] 14revAppend <-- [] 15revAppend --> <fun> 16revAppend* <-- [<poly>; <poly>; <poly>] 17revAppend* --> [<poly>; <poly>; <poly>] 18revAppend* --> [<poly>; <poly>; <poly>] 19revAppend* --> [<poly>; <poly>; <poly>] 20revAppend* --> [<poly>; <poly>; <poly>] 21- : int list = [3; 2; 1]
チュートリアルによると、これを回避する簡単な方法は引数に型制約を付けて単相な関数として定義することだそうです。以下のようにrevAppend
の引数をそれぞれint list
(整数のリスト)型に制限すれば実際の値を見ることができます。
ocaml
1# let rec revAppend (l1 : int list) (l2 : int list) = 2 match l1 with 3 [] -> l2 4 | v :: l1' -> revAppend l1' (v :: l2);; 5val revAppend : int list -> int list -> int list = <fun> 6 7# let rev l = revAppend l [];; 8val rev : int list -> int list = <fun> 9 10# rev [1; 2; 3];; 11revAppend <-- [1; 2; 3] 12revAppend --> <fun> 13revAppend* <-- [] 14revAppend <-- [2; 3] 15revAppend --> <fun> 16revAppend* <-- [1] 17revAppend <-- [3] 18revAppend --> <fun> 19revAppend* <-- [2; 1] 20revAppend <-- [] 21revAppend --> <fun> 22revAppend* <-- [3; 2; 1] 23revAppend* --> [3; 2; 1] 24revAppend* --> [3; 2; 1] 25revAppend* --> [3; 2; 1] 26revAppend* --> [3; 2; 1] 27- : int list = [3; 2; 1]
最後に、念のため補足しますと、トレースの最初の3行のところですが、
ocaml
1revAppend <-- [1; 2; 3] 2revAppend --> <fun> 3revAppend* <-- []
これは第1引数l1
が[1; 2; 3]
で、第2引数l2
が[]
であることを表しています。OCamlの関数はカリー化されており引数を1つだけとるため、このように表示されます。
投稿2021/05/15 13:27
編集2021/05/16 01:15総合スコア2046
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/05/16 13:43