如何从联合类型中解开泛型类型别名,从而使类型别名更具体?

时间:2019-03-08 16:33:55

标签: types elm algebraic-data-types unification parametric-polymorphism

我有类型Model,它描述了通用类型别名ModelFields的两种可能状态。我想从ModelFields类型的实例中提取通用Model记录。

type Model endValue stats
  = ShowEndValues (ModelFields Organism endValue)
  | ShowStatistics (ModelFields Rank stats)

type alias ModelFields object results =
  { results : List results
  , objects : List object
  , cellValue : results -> String
  , location : Maybe (Rank, Rank)
  }

getModelFields : Model endValue stats -> ModelFields object results
getModelFields model =
  case model of
    ShowEndValues modelFields ->
      modelFields 
    ShowStatistics modelFields ->
      modelFields

但是Elm不允许对每个案例表达式都说

TYPE MISMATCH - Something is off with the 1st branch of this `case` expression:

55|       modelFields 
          #^^^^^^^^^^^#
This `modelFields` value is a:

    ModelFields #Organism# #endValue#

But the type annotation on `getModelFields` says it should be:

    ModelFields #object# #results#

#Hint#: Your type annotation uses type variable `object` which means ANY type of
value can flow through, but your code is saying it specifically wants a
`Organism` value. Maybe change your type annotation to be more specific? Maybe
change the code to be more general?

所以我的问题是:我如何从ModelFields获得Model?还是我在做一些根本有缺陷的事情?

UPD。我要建模的详细信息。

我有Organism类型的对象。它们分为Rank个。我的服务器对Organism进行了成对分析,例如计算两个Similarity之间的DistanceOrganism。我想在不同页面上的两个表中显示这些分析的结果,一页用于Similarity分析,而一页用于Distance分析。这意味着该表应可重复使用以接受任何形式的分析结果。 另一方面,这些表有一个常见的模式。它们可以处于两种状态:

  1. 显示endValue之间的成对比较(Model中的Organism)的具体结果,因此表的行和列表示Organism
  2. stats组(Model s)之间显示统计值(例如Rank中的平均值或标准偏差,Organism中的Rank),在这种情况下,表格的行和列代表Rank

显示的Organismlocation取决于ModelFields的{​​{1}}字段。用户可以单击一个按钮,我想在我的location函数中更改update。此导航更改可能会在ShowEndValuesShowStatistics状态之间切换。这就是为什么我试图从ModelFields构造函数中解开Model的原因。我附上一个简单的插图,希望可以帮助阐明。table illustration

1 个答案:

答案 0 :(得分:1)

这确实是不可能的。

model函数中的getModelFields值将为Model endValue stats类型。这意味着它将是ShowEndValues变体,包含类型为ModelFields Organism endValue的值,或者是ShowStatistics变体,包含类型为ModelFields Rank stats的值。 case表达式的每个分支都解压缩一个变量并输出modelFields值。

现在,让我们尝试确定case表达式的类型。我们查看每个分支返回的类型,并尝试找到包含这两种类型的类型(统一它们)。乍一看,它看起来很有希望:两个值都以ModelFields a b的形式出现,因此我们将递归地尝试统一每个子类型。在这里,我们遇到了一个问题–第一种类型的a具有类型Organism,而第二种类型是Rank。没有同时使用OrganismRank的类型,因此编译失败。

注意:从错误消息中可以看到,Elm实际上试图用函数结果类型统一分支的类型。 (我描述了另一个方向,因为我认为更容易理解。)Elm遵循的方向也失败了,因为它会递归并尝试将具体的Organism类型与泛型object类型统一我们如何统一两种具体类型。