2016-03-03 29 views
3

前提:我認爲管道操作員只是語法糖,因此x |> f應該與f(x)完全一樣。F#管道和功能應用程序之間的神祕區別

類似,我認爲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預計其通過f匹配這反過來在推斷爲是因爲fileList一個string一個arg:obj是文件名的列表。 但是以下不起作用

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' 

我還以爲這兩個片段是在產生正確的代碼等同,但只有第一個做?

例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一致,因此我認爲它將統一,但這甚至不重要。爲什麼所有類型都有可能發生變化,因爲我再次相信這是純粹的句法替換?!

回答

7

類型推斷是按順序從上到下完成的。因此,在第一種情況下,fileList是第一個詞法參數。 然後在管道表達式中使用fileList是字符串列表的信息。要知道string是否是f的合法類型,則使用TestCaseData的簽名。正如所評論的,基於錯誤消息TestCaseData可能接受[<Params>] obj []使單個字符串參數有效。

在第二個版本沒有信息確定F以外的比TestCaseData的簽名的類型時使用,併爲此f被推斷爲類型obj []

類似的是在其它示例實現。只是相反。拉出該功能將刪除它應該是TestDelegate類型的信息。

在詞彙點唯一可用的信息是,這是unit->unit類型的函數。

當功能是在其中需要TestDelegate程序點使用。類型推斷測試函數是否可以用作TestDelegate,如果是這樣,推斷類型爲TestDelegate

+3

我還會注意到,根據錯誤消息判斷,'TestCaseData'函數可能不需要'obj',但''obj []',當你嘗試傳遞一個'obj'時工作,但當參數的類型還不知道時被推斷爲'obj []'。 –

+0

@FyodorSoikin好點,並相應地更新。謝謝 –

+0

這很有趣。因此,程序的有效性不僅僅取決於語法和(原則上)有效使用類型,而是實際依賴於當前實現的類型推斷機制。因此,給定的程序文本可能會變得有效/無效,這取決於微軟在編譯器中將來如何實現類型推斷?我發現,根據'f'和'x'的類型,'(|>)f x = f x'這樣的代數法則是有效的還是無效的。 –

相關問題