【问题标题】:Why are flexible types not allowed in record type definitions?为什么记录类型定义中不允许使用灵活类型?
【发布时间】:2015-03-26 10:49:49
【问题描述】:

我正在尝试这个:

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 -&gt; seq&lt;'action&gt;,这显然不会输入。我可以用第二个定义来做,在这种情况下has_action 有类型

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

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

【问题讨论】:

  • 如果您从 seq 之前删除 #,它将为我编译。
  • @MarkPattison 有一个很好的观点 - 删除 # 更容易 - 你为什么认为你需要它?
  • 关于您的更新 IMO,第三个参数是您记录的重要组成部分,所以不,我认为您不应该在这里删除它(顺便说一句:您不必输入它 - 您可以如果您愿意,请改用_)-如果您想知道(但在这里无济于事):您可以使用forall量化的唯一地方是(接口)成员(我在这里写过类似的问题:gettingsharper.de/2014/09/29/…)
  • 是的,看看has_parents 的类型,似乎没有办法绕过第三个类型参数。

标签: f# record flexible-type


【解决方案1】:

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

【讨论】:

  • 我不太明白:记录定义是类型定义;我没有定义任何价值观。而且我不确定您所说的“第二个选项在类型方面不是通用的”是什么意思?
  • 我的意思如下。通过定义一条记录,您正在定义一个类(在 IL / C# 术语中)。现在,如果您可以以通用方式定义成员,您将立即使其成为异类,因为您的记录的每个对象实例都将具有不同的运行时类型。
  • 不确定我们是否在谈论这些东西,但是:我没有看到问题,因为从这个角度来看,我只想要一个合适的通用类。我实际上只是希望灵活类型会自动为我引入类型变量。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    这是因为编译器实现灵活类型的方式。根据 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
    

    简单地说,灵活是作为标准泛型实现的,因为它没有在左侧或类型参数侧命名,所以你会得到一个错误。这也适用于记录类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-03
      • 2018-07-27
      • 2017-11-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多