Mar*_*per 6 f# discriminated-union
我正在按照预期让我的DU工作有问题.我已经定义了一个新的DU,它具有类型<'a>的结果或者从System.Exception派生的任何Exception
open System
// New exceptions.
type MyException(msg : string) = inherit Exception(msg)
type MyOtherException(msg : string) = inherit MyException(msg)
// DU to store result or an exception.
type TryResult<'a, 't> =
| Result of 'a
| Error of 't :> Exception
//This is fine.
let result = Result "Test"
// This works, doing it in 2 steps
let ex = new MyOtherException("Some Error")
let result2 = Error ex
// This doesn't work. Gives "Value Restriction" error.
let result3 = Error (new MyOtherException("Some Error"))
Run Code Online (Sandbox Code Playgroud)
我无法理解为什么它允许我创建一个"错误",如果我分两步,但当我在一行上做同样的事情时,我得到一个值限制错误.
我错过了什么?
谢谢
UPDATE
通过@kvb查看帖子,每次我需要创建一个错误时添加类型信息似乎有点冗长,所以我把它包装成另一个创建错误并且更简洁的方法.
// New function to return a Result
let asResult res : TryResult<_,Exception> = Result res
// New function to return an Error
let asError (err : Exception) : TryResult<unit,_> = Error(err)
// This works (as before)
let myResult = Result 100
// This also is fine..
let myResult2 = asResult 100
// Using 'asError' now works and doesn't require any explicit type information here.
let myError = asError (new MyException("Some Error"))
Run Code Online (Sandbox Code Playgroud)
我不确定用'单位'指定错误是否会产生任何我尚未预见到的后果.
TryResult<unit,_> = Error(err)
Run Code Online (Sandbox Code Playgroud)
考虑这种轻微的变化:
type MyOtherException(msg : string) =
inherit MyException(msg)
do printfn "%s" msg
let ex = new MyOtherException("Some Error") // clearly, side effect occurs here
let result2 = Error ex // no side effect here, but generalized value
let intResults = [Result 1; result2]
let stringResults = [Result "one"; result2] // can use result2 at either type, since it's a generalized value
let result3 = Error (MyOtherException("Some Error")) // result would be of type TryResult<'a, MyOtherException> for any 'a
// In some other module in a different compilation unit
let intResults2 = [Result 1; result3] // why would side effect happen here? just using a generic value...
let stringResults2 = [Result "one"; result3] // likewise here...
Run Code Online (Sandbox Code Playgroud)
问题是它看起来像result3一个值,但.NET类型系统不支持通用值,它只支持具体类型的值.因此,MyOtherException每次使用时result3都需要调用构造函数; 然而,这会导致任何副作用不止一次发生,这将是令人惊讶的.正如Ringil建议的那样,您可以通过告诉编译器将表达式视为值来解决此问题:
[<GeneralizableValue>]
let result3<'a> : TryResult<'a,_> = Error(new MyOtherException("Some Error"))
Run Code Online (Sandbox Code Playgroud)
只要构造函数没有副作用,这就没问题.