数组模式匹配

Tom*_*end 3 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|]
Run Code Online (Sandbox Code Playgroud)

问题似乎是循环继续并导致堆栈溢出.有可能这样做吗?

Van*_*oiy 8

我想你是想这样做的:

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

[|A; A; B|] |> Array.sumBy toInteger
Run Code Online (Sandbox Code Playgroud)

在模式匹配中,您可以使用数组模式:例如,[|a; b; c|]匹配三元素数组.但是没有::数组的运算符,所以使用数组就像使用列表一样繁琐.这是因为你不能将数组的尾部作为新数组而不复制它.

问题代码存在许多问题:

  • 由于超出了数组的范围,它崩溃了.这是因为您没有验证.[1..]切片是否存在.
  • 它不是尾递归.这可能是您在长列表中看到堆栈溢出的原因.
  • 两个功能混合在一个功能中,使得阅读变得复杂:转换为整数和求和.
  • 编译器无法验证模式匹配是否涵盖所有情况,因此它会发出警告.
  • 如前所述,复制数组成本很高.该算法在数组长度上具有O(n ^ 2),使得它对于长数组来说非常昂贵.与Array.sumBy索引到数组的尾递归函数不同,它不需要复制数组.

这里问题的核心是数组和单链接的不可变列表之间的区别.数组适合通过增加索引(Array.sumBy内部执行)来迭代它们,而列表允许将它们的尾部视为独立列表而不进行任何复制(哪个List.sumBy does internally).通常最好按照预期的方式使用每个数据结构.