我在 F# 中有一个函数列表,它们都是类型(float -> float -> float -> float)。我想对序列进行某种折叠以获得一个函数,该函数返回所有函数的总和。
例如,我可以将值 1.0、2.0 和 3.0 传递给列表中的每个函数,并从每个函数中获取一个返回值。然后我可以计算所有这些值的总和。但是,我想概括一下。
我知道如何递归地做到这一点,但我觉得它应该在一行中是可行的。有没有一种简洁的方法来完成这项任务?
@Lee 的解决方案是您正在寻找的单线。如果您想保存一些字符,您可以使用List.sumBy
which 首先将给定函数应用于列表的元素(类似于List.map
),然后对结果求和(就像List.sum
):
let sumAll (fs:(_ -> _ -> _ -> float) list) a b c =
List.sumBy (fun f -> f a b c) fs
这个版本和 Lee 的版本都使用类型注释来指定列表中的函数 return float
。这是必需的,因为否则编译器不知道您要使用哪种数字求和List.sum
(浮点数、整数等)。需要解决这种歧义以编译该函数。
或者,您可以将函数标记为inline
,然后在调用它时将其内联(它适用于多种不同的数字类型)。您还可以将fs
参数作为最后一个传递并使用偏函数应用程序:
let inline sumAll a b c = List.sumBy (fun f -> f a b c)
现在您可以使用流水线调用它,如下所示 fs |> sumAll 1 2 3
:
let sumAll (fs: (float -> float -> float -> float) list) a b c = List.map (fun f -> f a b c) fs |> Seq.sum
@Lee 和 @Tomas 的答案很棒,但还有更短的方法。
(a, b, c)
如果您可以在调用时以三元组的形式传递:
let inline sumAll() = (|||>) >> List.sumBy
// usage
let predicates =
[
fun a b c -> a
fun a b c -> b * 42.0 - c
]
let ret1 = predicates |> sumAll()(1.0, 2.0, 3.0)
它也将是通用的:
let predicates2 =
[
fun a b c -> c - 10
fun a b c -> a + c * 42
]
let ret2 = predicates2 |> sumAll()(1, 2, 3)
一种支持咖喱参数的更易读的方式:
let sumAllCurried a b c = (a,b,c) |> (|||>) |> List.sumBy<_, float>
// usage
let ret3 = predicates |> sumAllCurried 1.0 2.0 3.0
请注意,我使用类型参数 onList.sumBy
因为它看起来比为f
.