Erlang 的 'case' 表達式應採用/改編 Algol 68 的一個概念,在 Erlang 中這會嚴格地泛化 'cond'。
目前,'case' 表達式的形式為
'case' Expression 'of'
Pattern ['when' Guard] '->' Expression
{';' Pattern ['when' Guard] '->' Expression}...
'end'
眾所周知,Algol 68 有
if .. then .. {elif .. then ..}... [else ..] fi
表達式。比較不為人知的是,它對於 case 表達式也有類似的結構,
case .. in ... {ouse .. in ..}... [out ..] esac
其中 “ouse”(來自 “OUt caSE”)讓您可以迭代 case 匹配過程,並且只需要一個 ‘esac’。
此提案採用 Algol 68 的概念。修訂後的格式為
'case' Expression 'of'
Pattern ['when' Guard] '->' Expression
{';' Pattern ['when' Guard] '->' Expression}...
{';' 'or' 'case' Expression 'of'
Pattern ['when' Guard] '->' Expression
{';' Pattern ['when' Guard] '->' Expression}...}...
'end'
考慮這個範例
suffix(P, Suffix, List)
when is_function(P, 2), is_list(Suffix) ->
suffix_loop(P, Suffix, List).
suffix_loop(P, Suffix, List) ->
case equal(P, Suffix, List)
of true -> true
; false -> case List
of [_|Tail] -> suffix_loop(P, Suffix, Tail)
; [] -> false
end
end.
根據此提案,我們可以這樣寫
suffix_loop(P, Suffix, List) ->
case equal(P, Suffix, List)
of true -> true
; or case List
of [_|Tail] -> suffix_loop(P, Suffix, Tail)
; [] -> false
end.
其中所有要選擇的替代方案都具有相同的縮排。
舊的類似 Lisp 的 'cond' 提案已不再真正需要。取代
cond
C1 -> B1
; C2 -> B2
...
; Cn -> Bn
end
寫成
case C1 of true -> B1
; or case C2 of true -> B2
...
; or case Cn of true -> Bn
end
這裡失去的是檢查不是 'true' 的結果必須是 'false',但這項工作現在可以由 Dialyzer 完成。這當然比 'cond' 笨拙,但它達到了主要目的,即透過一系列布林值表達式,從邏輯上(因此在相同的縮排層次上)的一組選擇中進行選擇,但它在嚴格意義上更具通用性。它允許您將布林值表達式與守衛(包括未來任何守衛的泛化)結合使用,並且允許您根據任何形式的模式匹配(而不僅僅是布林值)進行選擇。
這比 'cond' 笨拙,但過度使用布林值,而應該使用一些更能顯示意圖的列舉,是一種已經被認可超過 20 年的反模式。如果存在 'cond',人們會有很強烈的壓力去編寫返回布林值結果的函數,而其他東西可能更有用,只是為了讓他們可以使用 'cond'。
舉例來說,假設我們希望在電壓為正常時繼續,在電壓低且沒有緊急情況時關閉設備,或者在電壓低且有緊急情況時將速度設定為慢速。
使用 cond
cond voltage_nominal() -> continue_operations()
; in_emergency() -> set_speed_slow()
; true -> shut_device_down()
end
使用 case
case voltage() of nominal -> continue_operations()
; or case status() of emergency -> set_speed_slow()
; normal -> shut_device_down()
end
當以這種方式表達時,我個人覺得更容易意識到“低”不是“正常”的反義詞;電壓不正常可能是高。所以我們真的應該有
case voltage() of nominal -> continue_operations()
; high -> WHAT DO WE DO HERE?
; or case status() of emergency -> set_speed_slow()
; normal -> shut_device_down()
end
因此,提供 'cond' 的“扁平”結構,同時巧妙地鼓勵 'case' 的多向思維的方法是有價值的。您可以說我支持 'ouse' 的程度不及反對 'cond' 和過度使用布林值的程度。
我讀了太多“為什麼 Erlang 沒有 if”的電子訊息,突然想起了“Algol 68 可以使用 'case' 來做到這一點”。
主要問題是如何在 Erlang 中拼寫 ‘ouse’。我的第一個偏好是 ‘or case’,但這行不通。我不喜歡 “; or case”,而且非常樂意看到更好的東西。實際上,“; case” 也許可以勝任,我只是覺得這有點太容易出錯了。
所有現有的 Erlang 程式碼在語意不變的情況下仍然可以接受。實作將完全在剖析器中進行,因此即使是檢查 AST 的工具也不會受到影響。
目前還沒有。它將完全在剖析器中進行。
本文檔已放置於公共領域。