2015-10-13 64 views
3

我刚开始摆弄Erlang。 我见过很多,其中模式匹配的函数声明中使用的例子,像这样:Erlang函数重载

factorCount (N) -> 
    Sqrt = math:sqrt (N), 
    ISqrt = trunc(Sqrt), 
    if ISqrt == Sqrt -> factorCount (N, ISqrt, 1, -1); 
     true   -> factorCount (N, ISqrt, 1, 0) 
    end. 

factorCount (_N, ISqrt, Candidate, Count) when Candidate > ISqrt -> Count; 
factorCount (N, ISqrt, Candidate, Count) -> 
    case N rem Candidate of 
     0 -> factorCount (N, ISqrt, Candidate + 1, Count + 2); 
     _ -> factorCount (N, ISqrt, Candidate + 1, Count) 
    end. 

为什么做这样? 例如

factorCount (_N, ISqrt, Candidate, Count) when Candidate > ISqrt -> Count; 
factorCount (N, ISqrt, Candidate, Count) -> 

为什么这不仅仅是一个函数的内部条件呢?

+0

你得已经很好的答案,我也将是添加,因为二郎神使用递归功能广泛,可以很方便地分开在不同的条款递归的不同的情况:这样你在第一线的测试案例,和递归在每个子句的最后一行调用(或基本情况的返回值),每个子句都有一些注释,它更容易阅读和维护。 – Pascal

回答

4

一个原因是可读性和可维护性。函数内部的条件倾向于使代码由于额外的缩进而蠕变到正确的位置,并且与身体中的额外条件结合使得更长的函数更难以阅读,推理和维护。

另一个原因是,功能常有的先决条件,而后卫往往可以帮助表达这些先决条件更清楚不是嵌入在函数体中的代码。

还有一个原因是模式匹配的参数总是发生在函数被调用时,因为这基本上是函数参数如何获得它们的绑定,所以在警卫中使用这些绑定值是很自然的。卫兵是模式匹配的一种扩展,允许您检查模式匹配无法检查的事情。

3

此外Steve'sanswer,这将是比较明显的,如果我重写代码:

factorCount(_N, ISqrt, Candidate, Count) 
    when Candidate > ISqrt -> 
    Count; 
factorCount(N, ISqrt, Candidate, Count) 
    when N rem Candidate =:= 0 -> 
    factorCount(N, ISqrt, Candidate + 1, Count + 2); 
factorCount(N, ISqrt, Candidate, Count) -> 
    factorCount(N, ISqrt, Candidate + 1, Count). 

它成为代码更加明显,你结合的图案带着卫兵匹配:

merge([{K, V1} | T1], [{K, V2} | T2]) -> 
    [{K, [V1, V2]} | merge(T1, T2)]; 
merge([{K1, V1} | T1], [{K2, _} | _] = L2) 
    when K1 < K2 -> 
    [{K1, [V1]} | merge(T1, L2)]; 
merge(L1, [{K2, V2} | T2]) -> 
    [{K2, [V2]} | merge(L1, T2)]; 
merge(L1, []) -> 
    [{K, [V]} || {K, V} <- L1]. 

会如果我将第二个和第三个函数子句组合在一起,只是为了在函数子句中进行比较,没有多大意义。

+1

但是,老实说[this](https://gist.github.com/Lol4t0/8410e791343730efb89f)对我来说更好 – Lol4t0

+1

我认为Hynek的缩进看起来很丑,而Lol4t0的缩进看起来很不错,但是使用'if's和冗余最后的测试使它看起来像来自程序语言。 –

+0

@NathanielWaisbrot那不是多余的测试而是明确的测试。显式总是优于隐式。 – Lol4t0