试图理解F#中的Choice类型

TBo*_*one 10 generics f# discriminated-union

我一直在努力理解Scott Wlaschin在RoP文章中的代码:

http://fsharpforfunandprofit.com/posts/railway-oriented-programming-carbonated/

他在F#中使用了Choice1Of2和Choice2Of2类型.当我遇到以下情况时,我试图通过调试它们来研究如何利用这些东西:

module TestModule
open Microsoft.VisualStudio.TestTools.UnitTesting

// generic union type (like Choice1Of2, I think)
type Things<'a> =
    | Thing of 'a

// explicit union type (for comparison)
type Numbers =   
    | Integer of int

[<TestClass>]
type Tests() =

    // method to make a Choice1Of2 (from the article)
    let makeChoice (a : string) : Choice<string, 'a> = 
        Choice1Of2 a

    [<TestMethod>]
    member public this.WhyYouNoHaveItemValueAndStuff() =      
        let choice1 = Thing "test"          // debug = Thing "this"
        let choice2 = Integer 3             // debug = Integer 3
        let choice3 = makeChoice "test"     // debug = Choice1Of2 w/Item = "test"
        let choice4 = Choice1Of2 "test"     // debug = Tests.choice4@24 ???

        // bogus test stuff below here
        let choices = (choice1, choice2, choice3, choice4)
        Assert.IsNotNull(choices)
Run Code Online (Sandbox Code Playgroud)

为什么当我直接创建Choice1Of2(choice4)时,我是否得到与选择3相同的调试结果.为什么使用一个方法使choice3需要获得与choice1和2相同的结果?

编辑:

似乎将选择4改为:

let choice4 : Choice<string, Object> = Choice1Of2 "test" 
Run Code Online (Sandbox Code Playgroud)

解决了.我完全不清楚为什么我需要它.作业的右侧与所设置的类型一样清晰.

Col*_*ull 8

Choice类型的定义如下

 type Choice<'a, 'b> =
      | Choice1Of2 of 'a
      | Choice2Of2 of 'b
Run Code Online (Sandbox Code Playgroud)

因此,当您构建Choice类型的实例时,choice4只使用其中一个腿,这实际上留下了一个'b调试器必须填充的漏洞(描述的类型),实际上在运行时它甚至无法确定该类型实际上是Choice<'a,'b>这样你将获得一个由FSharpFunc表示的临时类型.在几乎相同的方式类型推理机制将报告Choice<string, 'a>,其中'a表示孔,直到实例匹配过那么这将迫使你输入对方.提供内联类型签名,例如

 let choice4 : Choice<string, bool> = Choice1Of2 "test"
Run Code Online (Sandbox Code Playgroud)

意味着您正在填充漏洞并为调试器提供足够的信息以正确表示类型.

编辑(参见注释):choice3表示为Choice1Of2<string,obj>因为obj被认为是Top(最常见的类型).这是在耗尽所有其他选项时使用的类型推断机制后退类型.如果我们添加一些代码,例如

let result =
    match choice3 with
    | Choice1Of2 t -> t.GetHashCode()
    | Choice2Of2 t -> t  
Run Code Online (Sandbox Code Playgroud)

那么我们将得到Choice<string, int>的类型GetHashCode()int因此第二个匹配子句的结果必须是结果int的类型让表达式保持一致.