为什么记录类型定义中不允许使用灵活类型?

问题描述 投票:5回答:3

我正在尝试:

type TS1<'state, 'action> = {
    actions : 'state -> #seq<'action>
    move    : 'state -> 'action -> 'state
    state0  : 'state
}

但是类型检查器不会让我:

.../stdin(2,29):error FS0715: Anonymous type variables are not permitted in this declaration

但是,如果我展开弹性类型的定义,那很好:

type TS2<'state, 'action, 'actions when 'actions :> seq<'action>> = {
    actions : 'state -> 'actions
    move    : 'state -> 'action -> 'state
    state0  : 'state
}

我对必须添加'actions类型变量感到不满,因为它不像数学对象那样明显地连接到确定性转换系统。

我看不出在记录定义中允许使用灵活的类型会导致什么问题。有某种危险吗?我还有其他方法可以使我想清楚定义吗?

更新。我希望能够在利用已知实现的TS类型上编写函数。即,我希望能够定义一个函数

let has_action a ts s = Set.contains a <| ts.actions s

如果操作成员的类型为actions : 'state -> seq<'action>,则显然不会输入。我可以使用第二个定义来完成,在这种情况下,has_action的类型为>

has_action : a:'a -> ts:TS2<'s,'a,Set<'a>> -> s:'s -> bool when 'a : comparison

此示例的类型表明,TS1中的灵活类型可能无济于事。我无法避免在TS2中混乱的第三类型参数吗?在我看来,针对状态的动作集合的确切实现是实现细节,不应在类型中公开。

我正在尝试:类型TS1 = {动作:'状态-> #seq移动:'状态->'动作->'状态state0:'状态}但是类型检查器不会......>] >

这仅是当前编译器对允许的记录签名种类的实现的限制。例如,如果您在概念上以相同的方式定义类型,但是使用接口或抽象类而不是记录,则可以很好地编译:

type TS1<'state, 'action> = 
    abstract actions : 'state -> #seq<'action>
    abstract move    : 'state -> 'action -> 'state
    abstract state0  : 'state

您几乎在这里回答了您自己的问题...第二种方法有效,因为您引入了另一个类型参数,即您在'actions上进行了抽象。需要指出的是,您实际上无法在记录定义中定义通用值。考虑一下,第二个选项在类型上不是通用的,因为已定义'state'actions

这是由于编译器实现灵活类型的方式。根据F#规范第8.3节:

 Flexible type constraints #type may not be used on the right side of a type 
 abbreviation, because they expand to a type variable that has not been named 
 in the type arguments of the type abbreviation. For example, the following 
 type is disallowed:

       type Bad = #Exception -> int

简而言之,flexible是作为标准泛型实现的,由于尚未在左侧或类型实参侧进行命名,因此会出现错误。这也适用于记录类型。

f# record flexible-type
3个回答
1
投票

这仅是当前编译器对允许的记录签名种类的实现的限制。例如,如果您在概念上以相同的方式定义类型,但是使用接口或抽象类而不是记录,则可以很好地编译:


2
投票

您几乎在这里回答了您自己的问题...第二种方法有效,因为您引入了另一个类型参数,即您在'actions上进行了抽象。需要指出的是,您实际上无法在记录定义中定义通用值。考虑一下,第二个选项在类型上不是通用的,因为已定义'state'actions


0
投票

这是由于编译器实现灵活类型的方式。根据F#规范第8.3节:

 Flexible type constraints #type may not be used on the right side of a type 
 abbreviation, because they expand to a type variable that has not been named 
 in the type arguments of the type abbreviation. For example, the following 
 type is disallowed:

       type Bad = #Exception -> int
© www.soinside.com 2019 - 2024. All rights reserved.