可扩展记录在Elm 0.19中无用吗?

问题描述 投票:1回答:2

可扩展记录是最令人惊叹的Elm功能之一,但自从v0.16添加和删除字段is no longer available。这让我陷入了尴尬的境地。

考虑一个例子。我想给一个随机的东西t命名,可扩展记录为我提供了一个完美的工具:

type alias Named t = { t | name: String }

“好的,”编译器说。现在我需要一个构造函数,即一个为具有指定名称的东西配备的函数:

equip : String -> t -> Named t
equip name thing = { thing | name = name }  -- Oops! Type mismatch

编译失败,因为{ thing | name = ... }语法假定thingname字段的记录,但类型系统无法保证这一点。事实上,在Named t中,我试图表达相反的东西:t应该是没有自己的name字段的记录类型,并且该函数将此字段添加到记录中。无论如何,实现equip函数需要字段添加。

因此,似乎不可能以多态方式编写equip,但它可能不是一个如此重要的事情。毕竟,任何时候我都要为某些具体事情命名,我可以用手做。更糟糕的是,反函数extract : Named t -> t(删除命名事物的名称)需要字段删除机制,因此也不可实现:

extract : Named t -> t
extract thing = thing  -- Error: No implicit upcast

这将是非常重要的功能,因为我有大量的例程接受老式的未命名的东西,我需要一种方法来使用它们来命名。当然,对这些功能的大规模重构是不合格的解决方案。

最后,经过这个漫长的介绍,让我说出我的问题:

  1. 现代Elm是否可以替代旧的弃用字段添加/删除语法?
  2. 如果没有,上面有一些像equipextract这样的内置函数吗?对于每个自定义可扩展记录类型,我希望有一个多态分析器(一个提取其基本部分的函数)和一个多态构造函数(一个将基础部分与添加剂结合起来并生成记录的函数)。
  3. (1)和(2)的否定答案将迫使我以更传统的方式实施Named ttype Named t = Named String t 在这种情况下,我无法捕捉可扩展记录的目的。是否存在一个积极的用例,即可扩展记录发挥关键作用的场景?
elm
2个回答
3
投票

类型{ t | name : String }表示具有name字段的记录。它没有扩展t类型,而是扩展了编译器关于t本身的知识。

所以实际上equip的类型是String -> { t | name : String } -> { t | name : String }

更重要的是,正如您所注意到的,Elm不再支持向记录添加字段,因此即使类型系统允许您想要的内容,您仍然无法做到。 { thing | name = name }语法仅支持更新{ t | name : String }类型的记录。

同样,不支持从记录中删除字段。

如果你真的需要有可以添加或删除字段的类型,你可以使用Dict。其他选项是手动编写变换器,或创建和使用代码生成器(这是JSON解码样板的推荐解决方案一段时间)。

关于可扩展记录,Elm并不真正支持“可扩展”部分 - 唯一剩下的部分是{ t | name : u } -> u投影,所以也许它应该被称为范围记录。榆树docs本身承认可扩展性目前不是很有用。


2
投票

您可以使用t包装name类型,但与使用自定义类型的方法相比,它不会产生很大的不同:

type alias Named t = { val: t, name: String }

equip : String -> t -> Named t
equip name thing = { val = thing, name = name }

extract : Named t -> t
extract thing = thing.val
© www.soinside.com 2019 - 2024. All rights reserved.