我在许多情况下都遇到了 F# 的困难。我相信我没有掌握一些基本概念。我希望有人可以跟踪我的推理并找出我遗漏的(可能很多)东西。
假设我正在使用 Xunit。我想做的是,提供两个列表,成对应用 Assert.Equal
方法。例如:
Open Xunit
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 Assert.Equal test1 test2
编译器提示函数
Equal
没有一个参数。据我所知,map2
不应该提供 2 个参数吗?作为完整性检查,我在 f#immediate 中使用以下代码:
let doequal = fun x y -> printf "result: %b\n" (x = y)
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 doequal test1 test2;;
这似乎是相同的。
doequal
是一个 lambda,它采用 两个通用参数 并返回 单位 。 List.map2
将每个参数成对地传递给 lambda,我得到的输出正是我所期望的:result: true
result: true
result: false
那么什么给呢?来源显示
Xunit.Equal
具有签名 public static void Equal<T>(T expected, T actual)
。为什么我的参数不能直接映射到方法签名上?编辑一个
我认为两个变量x和y与元组(x,y)可以互换地构造和解构。所以我尝试了两种选择并得到了不同的结果。似乎第二个可能比第一个更远。
List.map2 Assert.Equal(test1, test2)
编译器现在提示“连续的参数应该是分隔的空格或元组”List.map2(Assert.Equal(test1, test2))
编译器现在提示“无法确定唯一的重载方法......可能需要类型注释” 最佳答案
我认为部分问题来自混合方法(OO 风格)和函数(FP 风格)。
F# 编译器尝试处理这两种方法,但偶尔需要一些帮助。
一种方法是用 FP 函数“包装”OO 方法。
// wrap method call with function
let assertEqual x y = Assert.Equal(x,y)
// all FP-style functions
List.map2 assertEqual test1 test2
如果不创建辅助函数,则在使用 lambda 调用“内联”方法时,通常需要将多个函数参数转换为一个元组:
List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2
当您在一行中混合方法和函数时,您经常会收到“连续的参数应该分开”错误。
printfn "%s" "hello".ToUpper()
// Error: Successive arguments should be separated
// by spaces or tupled
这告诉你编译器有问题,需要一些帮助!
您可以在方法调用周围使用额外的括号解决此问题:
printfn "%s" ("hello".ToUpper()) // ok
或者有时,使用反向管道:
printfn "%s" <| "hello".ToUpper() // ok
无论如何,包装方法通常值得一试,以便您可以交换参数以使其更适合部分应用:
// wrap method call with function AND swap params
let contains searchFor (s:string) = s.Contains(searchFor)
// all FP-style functions
["a"; "b"; "c"]
|> List.filter (contains "a")
请注意,在最后一行中,我必须使用括号使
contains "a"
优先于 List.filter
关于f# 签名匹配解释,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27693258/