f#签名匹配解释

coc*_*lla 4 f#

在很多情况下我都遇到了F#的困难.我相信我没有抓住一些基本概念.我希望有人可以追踪我的推理,并找出我所缺少的(可能很多)事情.

说我正在使用Xunit.我想做的是,提供两个列表,Assert.Equal成对应用方法.例如:

Open Xunit
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 Assert.Equal test1 test2
Run Code Online (Sandbox Code Playgroud)

编译器抱怨该函数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;;
Run Code Online (Sandbox Code Playgroud)

这似乎完全相同. doequal是一个带有两个通用参数和返回单位的lambda . List.map2将每个参数成对地交给lambda,我得到了我预期的输出:

result: true
result: true
result: false
Run Code Online (Sandbox Code Playgroud)

什么给出了什么?来源节目Xunit.Equal有签名public static void Equal<T>(T expected, T actual).为什么我的参数不会映射到方法签名上?

EDIT ONE 我认为两个变量x和y与一个元组(x,y)可以互换地构造和解构.所以我尝试了两个选项,得到了不同的结果.似乎第二个可能比第一个更进一步.

List.map2 Assert.Equal(test1, test2) 编译器现在抱怨"连续的参数应该是空格或tupled"

List.map2(Assert.Equal(test1, test2)) 编译器现在抱怨'无法确定一个独特的重载方法......可能需要一个类型注释'

Gru*_*oon 7

我认为问题的一部分来自混合方法(OO风格)和功能(FP风格).

  • FP样式函数具有由空格分隔的多个参数.
  • OO样式方法使用逗号分隔的parens和参数.
  • 其他.NET库中的方法总是使用"tuple"语法调用(实际上与元组略有不同),并且元组被认为是一个参数.

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
Run Code Online (Sandbox Code Playgroud)

如果您不创建辅助函数,则在使用lambda调用"inline"方法时,通常需要将多个函数参数转换为一个元组:

List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2
Run Code Online (Sandbox Code Playgroud)

当您在一行中混合方法和函数时,通常会得到"连续参数应该分开"错误.

printfn "%s" "hello".ToUpper()  
// Error: Successive arguments should be separated 
// by spaces or tupled
Run Code Online (Sandbox Code Playgroud)

这告诉你编译器有问题需要一些帮助!

您可以通过方法调用附加额外的问题来解决这个问题:

printfn "%s" ("hello".ToUpper())  // ok
Run Code Online (Sandbox Code Playgroud)

或者有时,使用反向管道:

printfn "%s" <| "hello".ToUpper() // ok
Run Code Online (Sandbox Code Playgroud)

无论如何,包装方法通常都值得做,以便您可以交换参数以使其更适合部分应用:

// 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")
Run Code Online (Sandbox Code Playgroud)

请注意,在最后一行中,我不得不使用parens优先于contains "a"overList.filter


Mar*_*ann 5

public static void Equal<T>(T expected, T actual)
Run Code Online (Sandbox Code Playgroud)

不带两个参数 - 它需要一个参数,这是一个带有两个元素的元组:(T expected, T actual).

试试这个:

List.map2 Assert.Equal(test1, test2)
Run Code Online (Sandbox Code Playgroud)