如何摆脱这种“无法概括”的错误?

时间:2018-02-15 13:21:53

标签: f#

我有这个界面声明

type IModel<'value, 'search, 'target when 'target :> IModel<'value, 'search, 'target>> =
    abstract token: string with get
    abstract value: 'value with get
    abstract search: 'search with get
    abstract GetEmpty: unit -> 'target
    abstract ReInitWith:  #IModel<_, 'search, _> -> 'target

type IModelSimple<'value, 'search> =
    inherit IModel<'value, 'search, IModelSimple<'value, 'search>>
    abstract Update:  ?token:string * ?value: 'value * ?search: 'search -> IModelSimple<'value, 'search>

和这个创建对象表达式的函数

let rec mkModelSimple<'value, 'search> vctor sctor token value search =
    {
        new IModelSimple<'value, 'search> with
            member this.token = token
            member this.value = value
            member this.search = search
            member this.GetEmpty() = mkModelSimple vctor sctor token (vctor()) (sctor())
            member this.ReInitWith (m: #IModel<_, 'search, _>) = mkModelSimple vctor sctor m.token this.value m.search
            member this.Update(?t:Token, ?v: 'value, ?s: 'search) =
                mkModelSimple vctor sctor (defaultArg t this.token) (defaultArg v this.value) (defaultArg s this.search)
    }

这很好用。

现在我想将上述类型改造成

type IModel<'value, 'target when 'target :> IModel<'value, 'target>> =
    abstract token: string with get
    abstract value: 'value with get
    abstract GetEmpty: unit -> 'target

type ISearchModel<'value, 'search, 'target when 'target :> ISearchModel<'value, 'search, 'target>> =
    inherit IModel<'value, 'target>
    abstract search: 'search with get
    abstract ReInitWith:  ISearchModel<_, _, _> -> 'target

type ISearchModelSimple<'value, 'search> =
    inherit ISearchModel<'value, 'search, ISearchModelSimple<'value, 'search>>
    abstract Update:  ?token:string * ?value: 'value * ?search: 'search -> ISearchModelSimple<'value, 'search>

与上述几乎相同,只是提取了“搜索方面”

现在我在实现创建对象表达式的函数时

let rec mkSearchModelSimple<'value, 'search> vctor sctor token value search =
    {
        new ISearchModelSimple<'value, 'search> with
            member this.token = token
            member this.value = value
            member this.search = search
            member this.GetEmpty() = mkSearchModelSimple vctor sctor token (vctor()) (sctor())
            member this.ReInitWith (m: #ISearchModel<_, 'search, _>) = mkSearchModelSimple vctor sctor m.token this.value m.search
            member this.Update(?t:Token, ?v: 'value, ?s: 'search) =
                mkSearchModelSimple vctor sctor (defaultArg t this.token) (defaultArg v this.value) (defaultArg s this.search)
    }

我在方法This code is not sufficiently generic. The type variable 'a could not be generalized because it would escape its scope.上获得了臭名昭着的ReInitWith 这让我发疯了。对于一个我不明白为什么这个看似和其他直接的改变根本就会产生错误,另一方面是什么是试图通信的错误消息?

1 个答案:

答案 0 :(得分:5)

第二个示例的一个问题是此ISearchModel方法包含所有未绑定的泛型类型参数:

abstract ReInitWith: ISearchModel<_, _, _> -> 'target

在第一个示例中,第二个泛型类型绑定到包含接口的'search类型:

abstract ReInitWith:  #IModel<_, 'search, _> -> 'target

如果从第一个示例中删除该类型约束,则无法以完全相同的方式进行编译。

如果您在第一个示例中限制第二个泛型类型,则第二个示例有效:

type ISearchModel<'value, 'search, 'target when 'target :> ISearchModel<'value, 'search, 'target>> =
    inherit IModel<'value, 'target>
    abstract search: 'search with get
    abstract ReInitWith: ISearchModel<_, 'search, _> -> 'target

这会为mkSearchModelSimple生成以下类型签名:

val mkSearchModelSimple :
  vctor:(unit -> 'value) ->
    sctor:(unit -> 'search) ->
      token:string ->
        value:'value -> search:'search -> ISearchModelSimple<'value,'search>

注意:我将Token类型引用替换为string;它的定义没有提供。