2015-04-28 20 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#编译器处理,因此它们支持更强大的泛型约束 - 包括,说:“与+什么”的约束。

相关问题