为什么在记录类型定义中不允许使用灵活类型?
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 是作为标准泛型实现的,因为它没有在左侧或类型参数侧命名,所以你会得到一个错误。这也适用于记录类型。
我正在尝试这个:
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 是作为标准泛型实现的,因为它没有在左侧或类型参数侧命名,所以你会得到一个错误。这也适用于记录类型。