![](/img/trans.png)
[英]How do I debug rebar3 erlang in vscode with the erlang plugin?
[英]How do I check where my code gets stuck in Erlang?
我正在嘗試編寫一個函數,該函數接收列表,在列表中找到最大值的整數,然后將列表中的所有其他整數除以該值。
不幸的是,我的代碼卡在了某個地方。 例如,如果這是python,我可以輕松地編寫幾個不同的“打印件”,看看它卡在哪里。 但是,您如何在Erlang中做到這一點?
這是代碼。
highest_value([], N) ->
if
N =:= 0 ->
'Error! No positive values.'
end,
N;
highest_value([H|T], N) when H > N, H > 0 ->
highest_value([T], H);
highest_value([_|T], N) ->
highest_value([T], N).
divide(_L) -> [X / highest_value(_L, 0) || X <- _L].
對於打印,您可以只使用io:format/2
。 一樣。
highest_value([H|T], N) when H > N, H > 0 ->
io:format(">>> when H bigger than N~n"),
io:format(">>> H: ~p, T: ~p, N: ~p ~n", [H, T, N]),
highest_value([T], H);
highest_value(List) ->
highest_value(List, 0).
編輯
您弄錯的一件事是[H | T]
[H | T]
語法。 H
或head是列表中的第一個元素。 T
代表尾巴,或“其余列表”。 顧名思義,tail是一個列表(可以是一個空列表,但仍然是一個列表)。 因此,當您進行遞歸操作時,無需將T放入新列表中。
highest_value([H|T], N) when H > N ->
highest_value(T, H);
highest_value([_|T], N) ->
highest_value(T, N).
在您的舊代碼中,您調用了:
highest_value([T], N).
它使用一個元素創建了一個新列表,例如[[2,3,4,5]]
。 如果將其尾部放置,則將此僅元素列表作為頭部,並將空列表作為尾部。
另外,在第一個函數子句中,您有一個原子'Error! No positive values.'
'Error! No positive values.'
(單引號表示這只是一個長原子,而不是字符串),它永遠不會返回(您將始終返回N
)。 如果您想返回某個原子或N
,則取決於N
值,您可以擴展對函數子句的使用
highest_value([], 0) ->
'Error! No positive values.'
highest_value([], N) ->
N;
[...]
而且您必須使用0
初始化函數,這可能被認為是錯誤的模式。 您可以編寫並使用highest_value/1
為您執行此操作
highest_value(List) ->
highest_value(List, 0).
甚至使用此算法的修改形式:由於最大的數字將是列表中的數字之一,因此可以將第一個元素用作函數初始化。
highest_value(_List = [First|T]) when First > 0 ->
highest_value(T, First).
假設您現在不關心處理負數。
盡管通過print語句進行調試是很普遍的,甚至有時是有用的,並且io:format
可以在Erlang中用於此目的( 如前所述) ,但Erlang提供了應使用的強大的內置跟蹤功能。
假設您的highest_value/2
和divide/1
函數駐留在名為hv
的模塊中。 首先,我們在Erlang shell中編譯hv
:
1> c(hv).
{ok,hv}
接下來,我們使用Erlang的dbg
模塊啟用對hv
函數的跟蹤:
2> dbg:tracer().
{ok,<0.41.0>}
3> dbg:p(self(),call).
{ok,[{matched,nonode@nohost,26}]}
4> dbg:tpl(hv,c).
{ok,[{matched,nonode@nohost,5},{saved,c}]}
在命令2中,我們啟用調試跟蹤,在命令3中,我們指示我們要跟蹤當前進程中的函數調用(由self()
返回)。 在命令4中,我們使用內置的c
跟蹤規范在hv
模塊中的所有函數上創建一個調用跟蹤。
啟用調試跟蹤后,我們將調用hv:divide/1
並開始跟蹤輸出:
5> hv:divide([4,8,12,16]).
(<0.34.0>) call hv:divide([4,8,12,16]) ({erl_eval,do_apply,6})
(<0.34.0>) call hv:'-divide/1-lc$^0/1-0-'([4,8,12,16],[4,8,12,16]) ({erl_eval,
do_apply,
6})
(<0.34.0>) call hv:highest_value([4,8,12,16],0) ({hv,'-divide/1-lc$^0/1-0-',2})
(<0.34.0>) call hv:highest_value([[8,12,16]],4) ({hv,'-divide/1-lc$^0/1-0-',2})
(<0.34.0>) call hv:highest_value([[]],[8,12,16]) ({hv,'-divide/1-lc$^0/1-0-',2})
(<0.34.0>) call hv:highest_value([[]],[8,12,16]) ({hv,'-divide/1-lc$^0/1-0-',2})
...
首先,請注意,我縮寫了跟蹤輸出,因為在...
點處它已經處於無限循環中,並且跟蹤的其余部分與...
之前的兩個語句相同。
跟蹤輸出告訴我們什么? 第一行顯示了divid divide/1
函數的調用,第二行顯示了對divide/1
內部列表理解的調用。 然后,我們看到對highest_value/2
調用,首先將完整列表和N
設置為0。下一個調用很有趣:因為在遞歸調用highest_value/2
您的代碼將[T]
而不是T
作為第一個參數highest_value/2
, H
的值為[8,12,16]
,Erlang將其視為大於當前N
值4,因此下一個遞歸調用為:
highest_value([T], [8,12,16]).
並且由於T
為[]
,因此變為:
highest_value([[]], [8,12,16]).
在這里, H
是[]
, T
也是[]
。 H
不大於[8,12,16]
,因此在這一點之后所有剩余的遞歸調用都與此相同,並且遞歸是無限的。
為了解決這個問題,您需要正確地傳遞T
,如前所述 :
highest_value([H|T], N) when H > N, H > 0 ->
highest_value(T, H);
highest_value([_|T], N) ->
highest_value(T, N).
然后重新編譯,這也會重新加載您的模塊,因此,您還需要再次設置調試跟蹤:
5> c(hv).
{ok,hv}
6> dbg:tpl(hv,c).
{ok,[{matched,nonode@nohost,5},{saved,c}]}
7> hv:divide([4,8,12,16]).
(<0.34.0>) call hv:divide([4,8,12,16]) ({erl_eval,do_apply,6})
(<0.34.0>) call hv:'-divide/1-lc$^0/1-0-'([4,8,12,16],[4,8,12,16]) ({erl_eval,
do_apply,
6})
(<0.34.0>) call hv:highest_value([4,8,12,16],0) ({hv,'-divide/1-lc$^0/1-0-',2})
(<0.34.0>) call hv:highest_value([8,12,16],4) ({hv,'-divide/1-lc$^0/1-0-',2})
(<0.34.0>) call hv:highest_value([12,16],8) ({hv,'-divide/1-lc$^0/1-0-',2})
(<0.34.0>) call hv:highest_value([16],12) ({hv,'-divide/1-lc$^0/1-0-',2})
(<0.34.0>) call hv:highest_value([],16) ({hv,'-divide/1-lc$^0/1-0-',2})
** exception error: no true branch found when evaluating an if expression
in function hv:highest_value/2 (/tmp/hv.erl, line 5)
in call from hv:'-divide/1-lc$^0/1-0-'/2 (/tmp/hv.erl, line 15)
現在跟蹤顯示, highest_value/2
可以按預期工作,但是我們現在使用if
語句遇到了一個新問題,並且此問題的解決方法已經在另一個答案中進行了說明,因此在此不再贅述。
如您所見,Erlang的跟蹤功能遠比使用“打印調試”功能強大。
就Erlang的跟蹤功能而言,我在這里展示的內容幾乎沒有觸及表面,但是發現並解決問題已綽綽有余。
最后,請注意,使用lists:max/1
標准庫調用可以更輕松地實現模塊要執行的操作:
divide(L) ->
case lists:max(L) of
N when N > 0 ->
[V/N || V <- L];
_ ->
error(badarg, [L])
end.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.