F#:实现“try cast”功能,参数化的“子类型”约束不起作用

时间:2018-06-09 20:18:03

标签: c# f# c#-to-f#

我正在尝试在F#中实现“try cast”运算符。约束的子类型不起作用。

例如,我想用C#做什么:

static A TryCast<TSuper, TSub, A>(
    Func<TSub, A> f,
    Func<TSuper, A> g,
    TSuper x)
    where TSub : TSuper
    =>
    x is TSub sub ? f(sub) : g(x);

F#中的等价物应为:

let tryCast<'super, 'sub when 'sub :> 'super>
    (f : 'sub -> 'a) (g: 'super -> 'a) (x : 'super) : 'a =
        match x with
        | :? 'sub as sub -> f sub
        | x              -> g x

或者

... 
if x :? 'sub then f (x :?> 'sub) else g x

然而,它给了我一个错误“'sub”在“when”子句中被限制为总是'super'。 这似乎表明F#不支持这一点。我觉得奇怪的是我可以在C#中做到这一点。

所以问题是:这可以在F#中完成吗?

1 个答案:

答案 0 :(得分:2)

感谢链接解释它确实是F#限制: How to constrain one type parameter by another

我想分享我找到的针对具体案例的(次优)解决方法:

let tryCastWith
    (success : 'sub -> 'a) (fallback: 'super -> 'a) (x : 'super) : 'a =
    let o = box x
    if o :? 'sub then success (o :?> 'sub) else fallback x

更具体地说,我实际想要的功能是这样的:

let tryCast (x : 'super) : Choice<'sub, 'super> =
    tryCastWith Choice1Of2 Choice2Of2 x

使铸造与消费脱钩。为了使用第二个函数,有必要让F#推断'sub'或者给出一个显式类型注释。