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

时间:2015-03-26 10:49:49

标签: f# record flexible-type

我正在尝试这个:

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中凌乱的第三类参数?在我看来,状态的动作集合的确切实现是一个不应该在类型中公开的实现细节。

3 个答案:

答案 0 :(得分:2)

你几乎在这里回答了你自己的问题......第二个选项有效,因为你引入了另一个类型参数,即你在'actions上抽象。关键是,您需要的不能在记录定义中真正定义通用值。考虑到第二个选项在类型方面不是通用的,因为定义了'state'actions

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

bc

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