F# 为什么在文件之间移动代码时类型会改变

F# 为什么在文件之间移动代码时类型会改变,f#,inline,F#,Inline,我有两个文件。第一个文件名为RailwayCombinator.fs,其内容如下: module RailwayCombinator let (|Uncarbonated|Carbonated|) = function | Choice1Of2 s -> Uncarbonated s | Choice2Of2 f -> Carbonated f let uncarbonated x = Choice1Of2

我有两个文件。第一个文件名为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 
我还注意到,的签名根据它所在的文件而改变,但我不知道为什么签名会改变。在RailwayCombinator中的签名为:

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

开关1:('a->Choice您的
组合器的实现使用
+
运算符。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
let inline()开关1开关2 x=
将(开关1 x)、(开关2 x)与
|碳化s1,碳化s2->碳化(s1+s2)
|未碳化f1,碳化s2->碳化s2
|碳化s1,未碳化f2->碳化s1
|未碳化f1,未碳化f2->未碳化f1

内联
由F#编译器直接处理,因此它们支持更强大的泛型约束—包括一个表示“任何带+”的约束。

您的
组合器的实现使用了
+
操作符。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
let inline()开关1开关2 x=
将(开关1 x)、(开关2 x)与
|碳化s1,碳化s2->碳化(s1+s2)
|未碳化f1,碳化s2->碳化s2
|碳化s1,未碳化f2->碳化s1
|未碳化f1,未碳化f2->未碳化f1

inline
由F#编译器直接处理,因此它们支持更强大的通用约束,包括一个表示“任何带+”的约束.

猜测时,将函数标记为内联将解决此问题,因为+的默认值为int,但在第二种情况下,您使用字符串强制更改。猜测时,将函数标记为内联将解决此问题,因为+的默认值为int,但在第二种情况下,您使用字符串强制更改。
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>
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