数组模式匹配

时间:2017-04-19 10:03:46

标签: f# functional-programming

是否可以使用模式匹配迭代数组,就像我们对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|]

问题似乎是循环继续并导致堆栈溢出。是否可以这样做?

1 个答案:

答案 0 :(得分:8)

我认为你正在尝试这样做:

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)。通常最好按照预期的方式使用每个数据结构。

相关问题