2015-10-13 86 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