首页 > 解决方案 > 如何从联合类型中解开泛型类型别名,从而使类型别名更具体?

问题描述

我有 type 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 不允许它对每个 case 表达式说

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?

所以我的问题是:我如何ModelFieldsModel?还是我在做一些根本上存在缺陷的事情?

UPD。我正在尝试建模的详细信息。

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

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

显示哪个Ranks 或Organisms 取决于 的location字段ModelFields。用户可以单击一个按钮,我想更改location我的update功能。这种导航变化可能会在ShowEndValuesShowStatistics状态之间切换。这就是为什么我试图ModelFieldsModel构造函数中解开。我附上了一个简单的插图,希望它有助于澄清。表格插图

标签: typeselmalgebraic-data-typesunificationparametric-polymorphism

解决方案


这确实是不可能的。

函数中的modelgetModelFields将具有 type Model endValue stats。这意味着它要么是ShowEndValues包含 type 值的变体,要么是包含 typed 值ModelFields Organism endValue的变体。表达式的每个分支解包一个变体并输出值。ShowStatisticsModelFields Rank statscasemodelFields

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

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


推荐阅读