【发布时间】:2015-03-22 19:38:26
【问题描述】:
我一直在努力理解 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<string, obj>,它们的用法似乎相同。在choice3和choice4上使用: Choice<string, int>之类的类型注释,它们在调试信息中看起来也相同。 -
@Vandroiy 感谢回复。这确实迫使正确的行为。有必要还是很奇怪。
-
在我看来,这并不是关于正确的行为,而是关于您在调试器中观察到的内容。我的猜测是,您所看到的是choice4 具有不完全推断的类型,并且不完全推断的类型的内部表示与具有泛型参数的类型的内部表示不同。除非您能找到在代码中(与在调试器中不同)对这些绑定进行不同评估或类型检查的情况,否则我认为这只不过是 VS 实现细节。
-
@NateC-K 够公平的。我想你可能是对的,事情就是这样。我还在学习 f#,我只是假设有一些我不知道的东西。谢谢
-
迟到的反应,我遇到了 F# Choice,然后我意识到它与来自 Scala/Haskell 的类型相同:这是 scala 的文档:scala-lang.org/api/current/scala/util/Either.html。如果您搜索
either函数式编程,您应该会找到很多信息。它无处不在。我有点喜欢更好的Either,因为它迫使你认为 Right 始终是成功的路径,而 Left 是错误的分支。但是,Choice 更抽象。
标签: generics f# discriminated-union