如何遵循F#Lint的建议使用`id`

时间:2018-10-11 17:22:22

标签: linq f# static-analysis

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

这引起了F#短绒棉衫的两个投诉。 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 <布尔,布尔>'
但是这里有类型     ''a->'a'

有人可以说出这段代码如何更合理吗?

2 个答案:

答案 0 :(得分:5)

我建议使用F#ListSeq模块而不是LINQ方法。这样,您就可以使用'a -> 'a之类的F#类型代替System.Func<'a, 'a>,并且可以将id传递给forAll函数。如果您可以发布完整的示例,则可以轻松地为您提供完整的答案,但是我认为类似这样的事情与您使用LINQ所做的事情大致相当:

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

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

然后,您可以部分应用行比较器功能来为每种方案创建专门的比较功能,如下所示:

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

答案 1 :(得分:2)

如果使用正确数量的泛型类型参数创建id的实例,则可以提供标准函数System.Func作为参数。当使用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