如何从联合类型中解开泛型类型别名,从而使类型别名更具体?
Posted
技术标签:
【中文标题】如何从联合类型中解开泛型类型别名,从而使类型别名更具体?【英文标题】:How do I unwrap a generic type alias from a union type which makes the type alias more specific? 【发布时间】:2019-07-30 17:27:18 【问题描述】:我有类型Model
,它描述了泛型别名ModelFields
的两种可能状态。我想从Model
类型的实例中提取通用ModelFields
记录。
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?
所以我的问题是:我如何从Model
获得ModelFields
?还是我在做一些根本上存在缺陷的事情?
UPD。我正在尝试建模的详细信息。
我有Organism
类型的对象。它们被分组为Rank
s。我的服务器对Organism
s 进行了一些成对分析,例如在两个Organism
s 之间计算Similarity
和Distance
。我想在不同页面的两个表中显示这些分析的结果,一页用于Similarity
分析,另一页用于Distance
分析。这意味着该表应该可重复使用以接受任何形式的分析结果。
另一方面,这些表有一个共同的模式。它们可以处于两种状态:
-
显示
Organism
s 之间成对比较的具体结果(Model
中的endValue
),因此表格的行和列代表Organism
s。
在Organism
s 的组 (Rank
s) 之间显示统计值(例如,平均值或标准差,stats
in Model
),在这种情况下,表格的行和列代表Rank
s。
显示哪个Rank
s 或Organism
s 取决于ModelFields
的location
字段。用户可以单击一个按钮,我想在我的update
函数中更改location
。此导航更改可能会在ShowEndValues
和ShowStatistics
状态之间切换。这就是为什么我试图从Model
构造函数中解开ModelFields
。我附上一个简单的插图,希望它有助于澄清。
【问题讨论】:
这是an XY problem。你试图做的事情是不可能的,不清楚你想在更高的层次上完成什么,为什么你做出了你做出的选择来达到这个目标,主要是因为不清楚你为什么需要所有这些类型变量。如果您能解释这一点,则可能会建议您改用什么方法,但除此之外,很难给出“不,行不通”以外的答案,并像 Jan 那样详细说明其技术原因。 【参考方案1】:这确实是不可能的。
getModelFields
函数中的model
值将具有Model endValue stats
类型。这意味着它要么是ShowEndValues
变体,包含ModelFields Organism endValue
类型的值,要么是ShowStatistics
变体,包含ModelFields Rank stats
类型的值。 case
表达式的每个分支都解包一个变体并输出 modelFields
值。
现在,让我们尝试确定case
表达式的类型。我们查看每个分支返回的类型,并尝试找到包含这两种类型的类型(统一它们)。乍一看,它看起来很有希望:两个值都采用ModelFields a b
的形式,因此我们将递归地尝试统一每个子类型。这里我们遇到了一个问题——第一种类型的a
的类型为Organism
,而第二种类型为Rank
。没有Organism
和Rank
的类型,所以编译失败。
注意:从错误信息中可以看出,Elm 实际上试图将分支的类型与函数结果类型统一起来。 (我描述了另一个方向,因为我认为它更容易理解。)Elm 遵循的方向也失败了,因为它会递归并尝试将具体的 Organism
类型与通用的 object
类型统一起来,类似于我们尝试的方式统一两种具体类型。
【讨论】:
谢谢你的解释,Jan。所以我知道这是不可能的。我更新了我的问题。您能就如何更好地构建模型提供任何建议吗? 如果来自两个分支的数据都可以用于渲染到一个表中,该函数应该将其转换为该表可以使用的通用类型,例如Model endValue stats -> StatsMatrix
以上是关于如何从联合类型中解开泛型类型别名,从而使类型别名更具体?的主要内容,如果未能解决你的问题,请参考以下文章