【问题标题】:Array pattern matching数组模式匹配
【发布时间】:2017-04-19 10:03:46
【问题描述】:

是否可以像 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|]

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

【问题讨论】:

    标签: f# functional-programming


    【解决方案1】:

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

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

    【讨论】:

      猜你喜欢
      • 2012-05-10
      • 2015-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-09
      相关资源
      最近更新 更多