【问题标题】:F# Matching results of recursive calls using higher order functionsF#使用高阶函数匹配递归调用的结果
【发布时间】:2017-11-08 18:36:42
【问题描述】:

给定一个简单的函数,我们对递归调用的结果进行模式匹配,例如:

let rec sumProd = function
    | []      -> (0,1)
    | x::rest -> let (rSum,rProd) = sumProd rest
                 (x + rSum,x * rProd)

sumProd [2;5] //Expected (7, 10)

我将如何使用高阶函数将其更改为某些东西,例如foldBack?

let sumProdHigherOrder lst = 
    List.foldBack (fun x acc -> (acc + x, acc * x)) lst (0,0)

上面的方法看起来差不多,但是调用它会给出错误:The type 'int' does not match the type 'int * int'

sumProdHigherOrder [2;5] //Expected (7, 10)

我错过了什么?

【问题讨论】:

    标签: f#


    【解决方案1】:

    您缺少元组函数fstsnd

    List.foldBack (fun x acc -> (fst acc + x, snd acc * x)) [2;5] (0,1)
    // val it : int * int = (7, 10)
    

    或者更好的是,在 lambda 处分解元组。我看到你刚刚找到它:

    List.foldBack (fun x (s, m) -> (s + x, m * x)) [2;5] (0,1)
    

    还请注意,由于操作是可交换的,您可以直接使用fold

    List.fold (fun (s, m) x -> (s + x, m * x)) (0,1) [2;5] 
    

    这样会更有效率。

    【讨论】:

    • 这是有道理的。我自己的答案是一种愚蠢的做法吗?
    • 不,你的答案和这个基本一样。您正在分解 lambda 中的元组。我实际上会像你一样写它,而不是 fstsnd
    • 好的。但是,在您的示例中,我对 fstsnd 的机制有点困惑。那些只是为了告诉它在元组中的每个元素上使用不同的函数吗?然后我可以看到如何分解 lambda 中的元组会更好,除非你知道你只处理对?
    • 是的,完全正确。它读起来更好,当然如果你有一个超过两个元素的元组,没有其他方法。
    • 技术上还有另一种方法,但您必须定义自己的函数。例如,对于 3 元组,您可以定义 let firstOf3 (x, _, _) = x; let secondOf3 (_, y, _) = y; let thirdOf3 (_, _, z) = z,然后像使用 fstsnd 用于 2 元组一样使用这些函数。在少数情况下,这可能会导致代码更易于阅读。但大多数时候,这样做很愚蠢,您应该在要使用它的地方解构元组。
    【解决方案2】:

    对!当然,它不应该是通过列表传递的同一个累加器。盯着代码看了几分钟后,我想通了:

    let sumProdHigherOrder lst = 
        List.foldBack (fun x (acc,acc') -> (acc + x, acc' * x)) lst (0,1)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-22
      • 2021-10-24
      • 1970-01-01
      • 2021-03-13
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2014-08-16
      相关资源
      最近更新 更多