鑒于以下串列
List Records
這里Record是
type Record
= RecordA A
| RecordB B
和A和B是型別別名與pos欄位:
type alias A =
{ pos : Maybe Int
, type : Char
}
我將如何創建一個新的串列來編號后續A和B記錄?我想pos = 1在第一條A記錄中,pos = 2在第二條A記錄中,pos = 1在第一條B記錄中等等(原始串列中沒有pos欄位中的數字。)
這是一種允許變異的語言的解決方案。
let countA = 0;
let countB = 0;
for (el of my_array) {
el.pos = (el.type == 'A') ? countA : countB;
}
uj5u.com熱心網友回復:
您可以將任何使用可變變數的迭代演算法轉換為遞回演算法,只需將可變變數設為函式引數即可:
enumerate : List Record -> Int -> Int -> List Record
enumerate list countA countB =
case list of
[] ->
[]
(RecordA el) :: rest ->
RecordA { el | pos = Just countA } :: enumerate rest (countA 1) countB
(RecordB el) :: rest ->
RecordB { el | pos = Just countB } :: enumerate rest countA (countB 1)
然而,這不是尾遞回,因此會溢位較大串列上的堆疊。每次使用它時都必須指定初始計數也有點不方便。我們可以通過使用內部函式并向其添加累加器引數來解決這兩個問題:
enumerate : List Record -> List Record
enumerate list =
let
aux els acc posA posB =
case list of
[] ->
acc
(RecordA el) :: rest ->
aux rest (RecordA { el | pos = Just posA } :: acc) (posA 1) posB
(RecordB el) :: rest ->
aux rest (RecordB { el | pos = Just posB } :: acc) posA (posB 1)
in
aux list [] 0 0
雖然您在這里似乎有一些更深層次的資料建模問題,但它看起來也不像您的實際型別,所以希望您最終也能解決這個問題。這至少應該讓你更接近一點。
uj5u.com熱心網友回復:
懶惰的回應:從本質上講,地圖運算式可能會做你想做的事。我還沒有徹底檢查這個,因為我也懶得讓樣板讓它在 ellie 中實際編譯:
List.map (\n -> RecordA (A(Just n) 'a')) (List.range 1 5)
如果我理解正確,您有一個包含A和B型別的串列?然后,您可能希望對映射到串列((\n -> RecordA (A(Just n) 'a'))部分)上的函式中的型別進行模式匹配,或者構建兩個串列并將zip它們組合在一起。但正如@glennsl 已經說過的那樣,該設計留下了一些問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/322306.html
