【发布时间】:2025-11-27 19:50:03
【问题描述】:
前提:我认为管道运算符只不过是语法糖,因此x |> f应该与f(x)完全相同。
类似地,我认为f (fun x -> foo)等价于let g = fun x -> foo; f g
但显然有一些我不明白的差异。
示例 1:
static member contents =
let files = Directory.EnumerateFiles (__SOURCE_DIRECTORY__+ @"\foo\bar.txt")
let fileList = List.ofSeq files
fileList |> List.map (fun f -> TestCaseData(f).SetName(""))
这很好用:TestCaseData 期望 arg:obj 与 f 匹配,而 string 又被推断为 string,因为 fileList 是文件名列表。
但是以下不起作用
static member contents =
let files = Directory.EnumerateFiles (__SOURCE_DIRECTORY__+ @"\foo\bar.txt")
let fileList = List.ofSeq files
List.map (fun f -> TestCaseData(f).SetName("")) fileList
除了最后一行没有改变。突然f 被推断为obj [] 和TestCaseData 需要obj [] 类型的参数,因此我得到一个错误
Error 1 Type mismatch. Expecting a obj [] list but given a string list
The type 'obj []' does not match the type 'string'
我原以为两个 sn-ps 在生成正确代码方面是等效的,但只有第一个可以?!
示例 2:
[<TestCase("nonsense", TestName="Nonsense")>]
member x.InvalidInputs str =
let lexbuf = Microsoft.FSharp.Text.Lexing.LexBuffer<char>.FromString(str)
Assert.Throws<FatalError> (fun () -> ParsePkg.parse "Dummy path" lexbuf |> ignore)
|> ignore
最重要的是一切正常。
[<TestCase("nonsense", TestName="Nonsense")>]
member x.InvalidInputs str =
let lexbuf = Microsoft.FSharp.Text.Lexing.LexBuffer<char>.FromString(str)
let ff = fun () -> ParsePkg.parse "Dummy path" lexbuf |> ignore
Assert.Throws<FatalError> (ff)
|> ignore
如您所见,我所做的只是通过首先定义let ff = ...(例如出于可读性原因)来提取断言的参数,然后编译器突然指向(ff) 参数并抱怨:
Error 2 This expression was expected to have type TestDelegate but here has type unit -> unit
TestDelegate 是我在这里使用的一种 NUnit,它恰好与 unit->unit 重合,所以我认为无论如何它都会统一,但这并不重要。为什么类型有可能发生变化,因为我再次相信已经做了纯粹的句法替换?!
【问题讨论】:
标签: f# type-inference piping