F#管道和功能应用之间的神秘差异

时间:2016-03-03 16:19:29

标签: f# type-inference piping

前提:我认为管道操作符只是语法糖,因此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:objf匹配,而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 []被推断为TestCaseDataobj []需要Error 1 Type mismatch. Expecting a obj [] list but given a string list The type 'obj []' does not match the type 'string' 类型的参数,因此我收到错误

[<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

我原以为两个片段在产生正确的代码时是相同的,但只有第一个呢?

示例2:

[<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 参数并抱怨:< / p>

unit->unit

TestDelegate是我在这里使用的一种NUnit,它碰巧与{{1}}重合,所以我认为它无论如何都会统一,但这甚至都不重要。为什么这个类型有可能发生变化,因为我再次认为它已经完成了纯粹的语法替换?!

1 个答案:

答案 0 :(得分:7)

类型推断从上到下顺序完成。所以在第一种情况下,fileList是第一个词汇参数。 然后,在管道表达式中使用fileList是字符串列表的信息。要知道string是否是f的合法类型,则使用TestCaseData的签名。根据错误消息,TestCaseData可能会接受[<Params>] obj []使单个字符串参数有效。

在第二个版本中,在确定除TestCaseData的签名之外的f的类型时没有信息可用,因此f被推断为类型obj []

在另一个例子中也是如此。反过来说。拉出该函数会删除它应该是TestDelegate类型的信息。

在词汇点,唯一可用的信息是它是unit->unit类型的函数。

在需要TestDelegate的程序点使用该功能时。类型推断测试该函数是否可以用作TestDelegate,如果是,则推断类型为TestDelegate