2017-04-19 79 views
2

是否有可能像使用F#中的列表一樣使用匹配匹配來遍歷數組?我試過這樣的事情:數組模式匹配

type Alphabet = A | B 

let rec calc (l: Alphabet []) = match l with 
           |l when l.[0] = A -> 5+(calc l.[1..]) 
           |l when l.[0] = B -> 10+(calc l.[1..]) 
           |l when l = [||] -> 0 
calc [|A;A;B|] 

問題似乎是循環繼續,併產生一個stackoverflow。是否有可能這樣做?

回答

7

我認爲你正在試圖做到這一點:

let toInteger = function 
    | A -> 5 
    | B -> 10 

[|A; A; B|] |> Array.sumBy toInteger 

在模式匹配,你可以使用數組模式:例如,對一個三元素的數組[|a; b; c|]匹配。但是對於數組,沒有::運算符,因此使用列表的方式使用數組很麻煩。這是因爲您不能複製數組的尾部而將其作爲新數組。

有一些與問題的代碼問題:

  • 它崩潰,由於外出數組的邊界。這是因爲您沒有驗證.[1..]切片存在。
  • 它不是尾遞歸。這可能是你在長列表上看到堆棧溢出的原因。
  • 將兩個功能混合到一個功能中,使其閱讀變得複雜:轉換爲整數和求和。
  • 編譯器無法驗證模式匹配是否涵蓋所有情況,因此它會發出警告。
  • 正如之前所暗示的,數組的複製是昂貴的。這個算法在數組長度上有O(n^2),這使得它對於長陣來說非常昂貴。不像Array.sumBy,或者是一個尾部遞歸函數索引到數組中,根本不需要複製數組。

問題的核心在於數組和單鏈不可變列表之間的區別。數組適合通過增加一個索引(Array.sumBy內部執行)來迭代它們,而列表允許將它們的尾部作爲獨立列表對待,而不需要複製(其中List.sumBy does internally)。通常最好按照打算使用的方式使用每個數據結構。