2014-03-03 62 views
2

我试图在FSharp中创建一个函数,该函数将采用接口类型的参数和派生类型的参数,该类型的参数作为该接口的实现传递:包含静态类型转换的f#方法的泛型类型

简单的例子:

type IFoo = 
    abstract member Compare : IFoo -> bool 

type Foo = 
    interface IFoo with 
     member this.Compare _ = false 

let doCompare (a : IFoo) (b : IFoo) = a.Compare(b) 

let comp (x : IFoo) (y : #IFoo) = doCompare x (y :> IFoo) 
let comp2 (x : 'T) (y : #'T) = doCompare x (y :> 'T) 

我得到的通用版本(这里,COMP2)以下两个错误:

在参数:

This construct causes code to be less generic than indicated by its type annotations. 
The type variable implied by the use of a '#', '_' or other type annotation at or near '...' 
has been constrained to be type ''T'.

在铸造操作:

The static coercion from type 'T to 'T involves an indeterminate type based on information prior to this program point. 
Static coercions are not allowed on some types. Further type annotations are needed.

有没有一种方法,我可以解决这个问题,比创建使用“T” U的签名,并通过对象这显然是不安全的铸造其他?

此代码(与原来的代码,表明这个问题一起 - 这是一种用于在测试夹具包裹NSubstitute)可以用tryfsharp

回答

5

#的为亚型约束,即语法糖。 comp2相当于:

let comp2<'T, 'U when 'U :> 'T> (x:'T) (y:'U) = doCompare x (y :> 'T) 

不幸的是,'U :> 'T部分没有由类型系统(不能约束类型是一种类型的可变的子类型)的支持,所以这是不可能的。

+0

感谢您的解释。从这个解释(这不包括在错误消息:-)我找到了这个答案,它引用了语言规范:http://stackoverflow.com/a/3857528/59371 – marklam

+0

这是值得铭记的东西当处理子类型约束时:你是否确定需要将“T”的子类型作为参数,还是仅仅使用“T”就足够了?在许多情况下,函数参数会根据需要自动上传,从而使子类型约束变得冗余。 – Tarmil