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

Why are flexible types not allowed in record type definitions?

我正在尝试这个:

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

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

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

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

这是因为编译器实现灵活类型的方式。根据 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 是作为标准泛型实现的,因为它没有在左侧或类型参数侧命名,所以你会得到一个错误。这也适用于记录类型。