我正在尝试编写一个接收列表的函数,在列表中找到最高值的整数,然后用该值除以列表中的所有其他整数。
不幸的是,我的代码卡在某处。如果这是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].
答案 0 :(得分:2)
对于打印件,您只需使用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
或head是列表中的第一个元素。 T
代表尾巴,或者&#34;列表的其余部分&#34;。顾名思义,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.'
(单引号意味着这只是一个长原子,而不是一个字符串),它永远不会被返回(你将永远返回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).
这假设处理负数是你现在不关心的事情。
答案 1 :(得分:1)
虽然通过print语句进行调试很常见,有时甚至是有用的,并且io:format
可以在Erlang as already noted中用于此目的,但Erlang提供了强大的内置跟踪功能,您应该使用它。
假设您的highest_value/2
和divide/1
函数位于名为hv
的模块中。首先,我们在Erlang shell中编译hv
:
1> c(hv).
{ok,hv}
接下来,我们使用Erlang's dbg
module启用对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})
...
首先,请注意我缩写了跟踪输出,因为在...
点它已经处于无限循环中,并且跟踪的其余部分与...
之前的两个语句相同。 / p>
跟踪输出告诉我们什么?第一行显示divide/1
函数的调用,第二行显示divide/1
内对列表推导的调用。然后,我们会看到对highest_value/2
的调用,首先是完整列表,N
设置为0.下一个调用是有趣的:因为您的代码通过[T]
而不是{{1}作为递归调用T
的第一个参数,highest_value/2
具有值H
,Erlang认为它大于当前[8,12,16]
值4,所以下一个递归调用是:
N
由于highest_value([T], [8,12,16]).
为T
,因此变为:
[]
此处highest_value([[]], [8,12,16]).
为H
,[]
也为T
。 []
不大于H
,因此此后所有剩余的递归调用都与此相同,并且递归是无限的。
要解决此问题,您需要正确传递[8,12,16]
as already noted:
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
语句遇到了新问题,并且已经解释了此问题的解决方案in another answer所以我赢了在这里重复一遍。
正如您所看到的,Erlang的跟踪功能远比使用“打印调试”更强大。
就Erlang的追踪功能而言,我在这里展示的内容几乎没有表面,但它足以找到并解决问题。
最后,请注意,使用if
标准库调用,您可以更轻松地实现模块尝试执行的操作:
lists:max/1