试图了解 F# 中的 Choice 类型
Trying to understand the Choice type in F#
我一直在努力理解 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)
为什么我直接做Choice1Of2(choice4)调试出来的结果和choice 3不一样?为什么要用方法做choice3才能得到和choice1一样的结果& 2?
编辑:
好像要把choice4改成这样:
let choice4 : Choice<string, Object> = Choice1Of2 "test"
解决了。我完全不清楚为什么我需要它。赋值右侧一目了然,设置的是什么类型。
Choice类型定义如下
type Choice<'a, 'b> =
| Choice1Of2 of 'a
| Choice2Of2 of 'b
因此,当您像在 choice4
中那样构造 Choice 类型的实例时,您只使用了这些分支中的一个,这实际上留下了一个漏洞(描述 'b
的类型),调试器必须填写,事实上在运行时它甚至不能确定类型实际上是 Choice<'a,'b>
所以你会得到一些由 FSharpFunc 表示的临时类型。以几乎相同的方式,类型推断机制将报告 Choice<string, 'a>
其中 'a
代表漏洞,直到实例匹配,然后强制您键入另一侧。提供内联类型签名,例如
let choice4 : Choice<string, bool> = Choice1Of2 "test"
意味着您正在填补漏洞并为调试器提供足够的信息来正确表示类型。
编辑(见评论):choice3 表示为 Choice1Of2<string,obj>
因为 obj
被认为是顶部(最一般的类型)。这是在用尽所有其他选项时使用的类型推断机制回退类型。如果我们添加一些代码,例如
let result =
match choice3 with
| Choice1Of2 t -> t.GetHashCode()
| Choice2Of2 t -> t
那么我们将得到 Choice<string, int>
因为 GetHashCode()
的类型是 int
因此第二个匹配子句的结果必须是 int
对于 result让表达式保持一致。
我一直在努力理解 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)
为什么我直接做Choice1Of2(choice4)调试出来的结果和choice 3不一样?为什么要用方法做choice3才能得到和choice1一样的结果& 2?
编辑:
好像要把choice4改成这样:
let choice4 : Choice<string, Object> = Choice1Of2 "test"
解决了。我完全不清楚为什么我需要它。赋值右侧一目了然,设置的是什么类型。
Choice类型定义如下
type Choice<'a, 'b> =
| Choice1Of2 of 'a
| Choice2Of2 of 'b
因此,当您像在 choice4
中那样构造 Choice 类型的实例时,您只使用了这些分支中的一个,这实际上留下了一个漏洞(描述 'b
的类型),调试器必须填写,事实上在运行时它甚至不能确定类型实际上是 Choice<'a,'b>
所以你会得到一些由 FSharpFunc 表示的临时类型。以几乎相同的方式,类型推断机制将报告 Choice<string, 'a>
其中 'a
代表漏洞,直到实例匹配,然后强制您键入另一侧。提供内联类型签名,例如
let choice4 : Choice<string, bool> = Choice1Of2 "test"
意味着您正在填补漏洞并为调试器提供足够的信息来正确表示类型。
编辑(见评论):choice3 表示为 Choice1Of2<string,obj>
因为 obj
被认为是顶部(最一般的类型)。这是在用尽所有其他选项时使用的类型推断机制回退类型。如果我们添加一些代码,例如
let result =
match choice3 with
| Choice1Of2 t -> t.GetHashCode()
| Choice2Of2 t -> t
那么我们将得到 Choice<string, int>
因为 GetHashCode()
的类型是 int
因此第二个匹配子句的结果必须是 int
对于 result让表达式保持一致。