我如何按照 F# Lint 的建议使用 `id`

How can I follow F# Lint's suggestion to use `id`

我正在比较两个列表。由于我对 Linq 比 F# 更熟悉,所以我这样做了: let r1 = (rows1.Zip (rows2, fun r1 r2 -> rowComparer r1 r2)) .All (fun f -> f)

这引起了 F# linter 的两个抱怨。 Lint: If `rowComparer` has no mutable arguments partially applied then the lambda can be removed. Lint: `fun x -> x` might be able to be refactored into `id`.

其中,我能理解后者,并尝试了这个: let r1 = (rows1.Zip (rows2, fun r1 r2 -> rowComparer r1 r2)) .All id 但这让 F# 编译器抱怨:

这个表达式应该有类型 'System.Func<bool,bool>'
但这里有类型 ''a -> 'a'

有人能说说这段代码怎么能更正吗?

我建议使用 F# ListSeq 模块而不是 LINQ 方法。然后您将能够使用 F# 类型,例如 'a -> 'a 而不是 System.Func<'a, 'a>,并且您可以将 id 传递给 forAll 函数。如果你能 post 一个完整的例子,给你一个完整的答案会更容易,但我认为这样的事情大致相当于你用 LINQ 做的事情:

let compare (rowComparer: ('a * 'a) -> bool) rows = 
    Seq.zip rows >> Seq.map rowComparer >> Seq.forall id

这将创建一个函数,该函数接受两个序列并将第一个序列中的每个值与第二个序列中的相应值进行比较,从而生成一个布尔值序列。如果序列中的所有值都为真,则 returns 为真,否则 returns 为假。这是通过使用函数组合和部分应用来构建具有所需签名的新函数来实现的。

然后您可以部分应用行比较器函数来为您的每个场景创建专门的比较函数,如下所示:

let compareEqual = compare (fun (a,b) -> a = b) 
compareEqual [0; 1; 2] [0; 1; 2] // true
compareEqual [0; 1; 2] [2; 1; 2] // false

如果您使用正确数量的通用类型参数创建 System.Func 的实例,则可以提供标准函数 id 作为参数。使用 lambda 表达式时,F# 编译器会为您完成。

open System.Linq
let foo rowComparer (rows1 : seq<_>) (rows2 : seq<_>) =
    (rows1.Zip (rows2, fun r1 r2 -> rowComparer r1 r2)).All(System.Func<_,_>(id))
// val foo :
//   rowComparer:('a -> 'b -> bool) -> rows1:seq<'a> -> rows2:seq<'b> -> bool