F#歧视联盟类型问题
问题描述:
我遇到了让DU按预期工作的问题。我已经定义了一个新的杜其或者具有<类型“从System.ExceptionF#歧视联盟类型问题
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"))
衍生>或任何异常的结果,我不明白为什么它让我创造一个‘错误’,如果我分两步做,但是当我在一行上做同样的事情时,我得到一个值限制错误。
我在想什么?
由于
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"))
我不确定指定'单元'的错误是否会产生任何后果,我还没有预料到。
TryResult<unit,_> = Error(err)
答
考虑这个微小的变化:
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...
的问题是,它看起来像result3
是一种价值,但.NET类型系统不支持通用的值,它仅支持具体类型的值。因此,每次使用result3
时,需要调用MyOtherException
构造函数;然而,这会导致任何副作用发生超过一次,这将是令人惊讶的。作为Ringil建议,您可以解决此告诉编译器把表达式作为值反正:
[<GeneralizableValue>]
let result3<'a> : TryResult<'a,_> = Error(new MyOtherException("Some Error"))
这是罚款,只要在构造函数没有副作用。
答
你可以这样做:
let result3<'a> = Error (new MyOtherException("Some Error"))
编辑:
至于为什么你不能做到这一点一步到位,首先要注意这导致了同样的错误:
let result4 = Result (new MyOtherException("Some Error"))
像这样:
let result4 = Result ([|1;|])
但是,这个工程:
let result4 = Result ([1;])
关于什么的异常和阵列相似,但并不名单?这是他们的可变性。当您尝试使用可在单个步骤中进行修改的类型创建TryResult时,值限制会打扰您。
现在至于为什么两步过程解决了这个问题,这是因为构造函数使整个函数不可泛化,因为您正在将函数应用于构造函数。但将其分解为两个步骤解决了这一问题。它与案例2 here on MSDN类似。
您可以在上面的MSDN文章中阅读更多关于它的信息,以及this more indepth blog post中发生这种情况的原因。
谢谢。这是有道理的。我已经更新了我的问题,并添加了一个额外的错误创建方法,它似乎可以正常工作并保持一点整理。唯一的问题是,该类型现在指定为TryResult不知道这是否有任何不利因素。 –
Moog