2015-04-28 22 views
1

我有兩個文件。第一個文件,即所謂RailwayCombinator.fs的內容,分別是:當我在文件之間移動代碼時,爲什麼類型會改變

module RailwayCombinator 

    let (|Uncarbonated|Carbonated|) = 
     function 
     | Choice1Of2 s -> Uncarbonated s 
     | Choice2Of2 f -> Carbonated f 

    let uncarbonated x = Choice1Of2 x 
    let carbonated x = Choice2Of2 x 

    let either successFunc failureFunc twoTrackInput = 
     match twoTrackInput with 
     | Uncarbonated s -> successFunc s 
     | Carbonated f -> failureFunc f 

第二個文件,這就是所謂Program.fs的內容,分別是:

open RailwayCombinator 

    let carbonate factor label i = 
     if i % factor = 0 then 
     carbonated label 
     else 
     uncarbonated i 

    let fizzBuzz = 
     let carbonateAll = 
     carbonate 3 "Fizz" <+> carbonate 5 "Buzz" 

     carbonateAll 

我也有一個代碼塊:

let (<+>) switch1 switch2 x = 
    match (switch1 x),(switch2 x) with 
    | Carbonated s1,Carbonated s2 -> carbonated (s1 + s2) 
    | Uncarbonated f1,Carbonated s2 -> carbonated s2 
    | Carbonated s1,Uncarbonated f2 -> carbonated s1 
    | Uncarbonated f1,Uncarbonated f2 -> uncarbonated f1 

如果我把代碼塊放到名爲Program的文件中,它就編譯得很好。如果我把它放在RailwayCombinator中,我會在這條線上發現錯誤。

carbonate 3 "Fizz" <+> carbonate 5 "Buzz" 

的錯誤是:

This expression was expected to have type 
    int  
but here has type 
    string 

我也注意到,根據其所在的文件< +>簽名變了,但我不知道爲什麼簽名改變。當它在RailwayCombinator的簽名是:

val (<+>) : 
    switch1:('a -> Choice<'b,int>) -> 
    switch2:('a -> Choice<'c,int>) -> x:'a -> Choice<'b,int> 

當它在程序上的簽名改爲

val (<+>) : 
    switch1:('a -> Choice<'b,string>) -> 
    switch2:('a -> Choice<'c,string>) -> x:'a -> Choice<'b,string> 

那麼,爲什麼簽名變化?

+2

猜測,標記函數內聯可以解決這個問題,因爲+的默認值是int,但在第二種情況下,您使用強制進行更改的字符串。 –

回答

4

<+>組合子的實現使用+運算符。 F#編譯器不知道如何使這個泛型(.NET泛型沒有泛型約束,說類型應該是「帶有+運算符的任何東西」)。因此,F#編譯器根據使用運算符的定義下的第一段代碼是什麼選擇<+>的第一個類型。

可以解決,通過使定義在線:

let inline (<+>) switch1 switch2 x = 
    match (switch1 x),(switch2 x) with 
    | Carbonated s1,Carbonated s2 -> carbonated (s1 + s2) 
    | Uncarbonated f1,Carbonated s2 -> carbonated s2 
    | Carbonated s1,Uncarbonated f2 -> carbonated s1 
    | Uncarbonated f1,Uncarbonated f2 -> uncarbonated f1 

inline直接由F#編譯器處理,因此它們支持更強大的泛型約束 - 包括,說:「與+什麼」的約束。

相關問題