新增最大值和最小值核心函式。
目前 Erlang 語言沒有內建支援最大值和最小值運算。因此我們新增以下函式:
erlang:min(E1, E2)
,其效果和值與
(T1 = E1, T2 = E2, if T1 > T2 -> T2 ; true -> T1 end)
erlang:max(E1, E2)
具有相同的效果和值,
(T1 = E1, T2 = E2, if T1 > T2 -> T1 ; true -> T2 end)
但我們期望它們使用單一 VM 指令實作,並期望 HiPE 在具備條件移動的機器上使用條件移動。
當且僅當沒有本地定義的 max/2
(分別為 min/2
)時,max/2
(分別為 min/2
)上的 erlang:
模組前綴可以省略。
最大值和最小值是非常有用的運算。Erlang 沒有標準方式來表達它們,其結果可想而知:在 tool_utils
、tv_pg_gridfcns
、tv_pb
、tv_comm_func
、ssh_connection_handler
、bssh_connection_handler
、ssh_cli
、hipe_arm
、hipe_schedule
、hipe_ultra_prio
、hipe_ppc_frame
、?HIPE_X86_FRAME
(據推測,32 位元和 64 位元 PC 各一個)、hipe_sparc_frame
、erl_recomment
、erl_syntax_lib
、appmon_info
中都有 max/2
的定義,這個列表還在不斷增加。有數十個副本。min/2
的副本也幾乎一樣多。這還不包括可能使用不同名稱的副本。
這些運算不僅實用,編譯器實作它們也比程式設計師更有效率。如果 X < Y
可以是一個 VM 指令,那麼 min
和 max
也可以。以下是第一個草稿實作
OpCase(i_minimum): {
r(0) = CMP_GT(tmp_arg1, tmp_arg2)) ? tmp_arg1 : tmp_arg2;
Next(1);
}
OpCase(i_maximum): {
r(0) = CMP_GT(tmp_arg1, tmp_arg2)) ? tmp_arg2 : tmp_arg1;
Next(1);
}
警告:程式碼未經測試!除此之外,我不知道所有需要更新的地方,或者當新增指令時該如何更新。這些指令預期會像 < 和它的其他朋友一樣,前面加上一個 i_fetch
指令。
這比 Erlang 函式呼叫便宜得多,而且當涉及到兩個浮點數的最大值或最小值時,HiPE 更容易識別,並且可以轉換為比較和條件移動。
最重要的是消除了思考的障礙。當我寫 Fortran 時,我知道 max 和 min 已經存在數十年了,我可以自由地使用這些運算。當我寫 C 時,我知道這些運算不存在,而且傳統巨集存在問題,所以我會避免使用它們。作為一個實驗,我將 max() 和 min() 函式新增到我維護的 AWK 版本中。這很容易,結果是我現在有很多 AWK 程式碼無法被其他任何程式碼執行,因為這些運算非常方便。Erlang 沒有 文件記載的 最大值或最小值函式,除了 lists
模組中的函式之外,而且寫 lists:max([X,Y])
非常麻煩,足以讓大多數人卻步。
函式還是運算子?
我認為有充分的理由使用 格理論中的標準 /\
和 \/
符號。然而,在 EEPs 郵件列表中的討論顯示,社群分為:
這些運算能夠作為語言的標準部分使用比它們的名稱更重要,因此為了提高接受度,此 EEP 的第二個草稿改為內建函式。
最終讓我下定決心的是國際化的考慮:日本程式設計師可能使用鍵盤,其中 \
表示 或螢幕,其中 \
顯示為日圓符號,因此 /\
和 \/
對他們來說根本行不通。
我們不能使用 max
和 min
作為運算子,因為編譯器不允許將符號同時用作運算子和函式名稱,而且 max
和 min
作為函式名稱有很多用途。這正是我們在這裡試圖解決的問題。所以它們必須是函式名稱。
將新的函式新增到 erlang:
模組中並沒有什麼困難。
我不想在這裡寫 erlang:
前綴。對於某些函式,erlang:
前綴是可選的,這也不是什麼新鮮事。
我們想要的是,具有自己 max/2
和/或 min/2
定義的現有模組保持合法,然後只需刪除多餘的定義即可升級。
假設你想找到一組 2D 點的邊界框。(這是從 Wings3D 的程式碼改編而來。)
bounding_box([{X0,Y0}|Pts]) ->
bounding_box(Pts, X0,X0, Y0,Y0).
bounding_box([{X,Y}|Pts], Xlo,Xhi, Ylo,Yhi) ->
if X < Xlo -> Xlo1 = X, Xhi1 = Xhi
; X > Xhi -> Xlo1 = Xlo, Xhi1 = X
; true -> Xlo1 = Xlo, Xhi1 = Xhi
end,
if Y < Ylo -> Ylo1 = Y, Yhi1 = Yhi
; Y > Yhi -> Ylo1 = Ylo, Yhi1 = Y
; true -> Ylo1 = Ylo, Yhi1 = Yhi
end,
bounding_box(Pts, Xlo1,Xhi1, Ylo1,Yhi1);
bounding_box([], Xlo,Xhi, Ylo,Yhi) ->
{{Xlo,Ylo}, {Xhi,Yhi}}.
使用最大值和最小值運算子,這將變成
bounding_box([{X,Y}|Pts], Xlo,Xhi, Ylo,Yhi) ->
bounding_box(Pts, min(X,Xlo), max(X,Xhi),
min(Y,Ylo), max(Y,Yhi));
bounding_box([], Xlo,Xhi, Ylo,Yhi) ->
{{Xlo,Ylo}, {Xhi,Yhi}}.
沒有問題。如果模組已經有 max/2
或 min/2
,則需要使用 erlang:
前綴才能取得新的函式。
我對 BEAM 或編譯器的了解不夠深入,無法提供實作,但上面提供的指令定義證明對於那些了解的人來說應該不難。如果這個 EEP 被接受,我會很樂意為這些運算子撰寫文件。
本文檔已置於公共領域。