Elm 中的多态记录类型
Polymorphic Record Type in Elm
在 Elm 中可以实现以下功能吗?
func : a -> {a | id : Int}
func x = { x | id = 123 }
编译失败,因为 a
也是 多态;它认为它可以是任何东西,包括非记录类型。我如何告诉编译器 a
是一种记录类型,但我们不知道其任何字段? (老实说,虽然 {a | id : Int}
就足够了)。
我试过了...
type alias Record a = {a}
func : Record a -> { a | id : Int }
func : {a} -> {a | id : Int}
func x = { x | id = 123 }
两者都因语法错误而失败。可以对 Elm 说 "this type is a record, but I don't know anything else" 吗?
解决以下回复:
If it was a record without any specific fields, you wouldn't be able to do anything record-like with it anyway, so it doesn't seem useful to be able to express that.
在我的例子中,我试图用未知字段的记录做一些类似记录的事情,所以说不能用它们做任何事情是不正确的。
You can't dynamically add fields to a record.
我没有动态地向记录添加字段,我正在创建一个与现有记录匹配的新记录,除了它有一个 id
字段值为 123
.
That's just not a thing records do, probably because it would be really awkward if a already had an id field.
这似乎是您推理的实际内容,但我认为它不是很有说服力。为什么那会很尴尬?以这种方式工作似乎是迄今为止最明显的工作方式?
If this isn't what you want, then it seems this is a case of the XY problem
顺便说一句,但每次我在 Elm 的类型系统中遇到 annoyances/weaknesses 都是我的错,而不是 Elms。
如果它是一条没有任何特定字段的记录,那么无论如何您都无法用它做任何类似记录的事情,因此能够表达它似乎没有用。
您不能向记录动态添加字段。这不是记录所做的事情,可能是因为如果 a
已经有一个 id
字段会很尴尬。所以为了分配 id
你需要知道记录有一个 id
字段。因此函数的正确类型是:
func : {a | id : Int} -> {a | id : Int}
如果这不是您想要的,那么这似乎是 the XY problem
的情况
不,Elm 没有办法让类型注释在不指定任何字段的情况下指示类型是记录。但是,即使没有类型注释,Elm 也没有语法来执行您想要的操作。 { a | id = 123 }
是 record update 语法,它不支持向记录添加字段(并且,从 Elm 0.19 开始,也不支持更改字段类型)
据我所知,Elm 没有允许您生成带有附加字段的记录副本的语法。
以上答案是正确的,而且更符合地道,但我认为您可以通过使用新字段定义记录的类型别名来完成您想要的。当然,您必须为所有可能的记录类型定义联合类型 C
。
type alias A = { a : String }
type alias B = { a : Int }
type C = Foo A
| Bar B
type alias D = { a : C, d : Int }
fn : C -> Int -> D
fn a y = D a y
在 Elm 中可以实现以下功能吗?
func : a -> {a | id : Int}
func x = { x | id = 123 }
编译失败,因为 a
也是 多态;它认为它可以是任何东西,包括非记录类型。我如何告诉编译器 a
是一种记录类型,但我们不知道其任何字段? (老实说,虽然 {a | id : Int}
就足够了)。
我试过了...
type alias Record a = {a}
func : Record a -> { a | id : Int }
func : {a} -> {a | id : Int}
func x = { x | id = 123 }
两者都因语法错误而失败。可以对 Elm 说 "this type is a record, but I don't know anything else" 吗?
解决以下回复:
If it was a record without any specific fields, you wouldn't be able to do anything record-like with it anyway, so it doesn't seem useful to be able to express that.
在我的例子中,我试图用未知字段的记录做一些类似记录的事情,所以说不能用它们做任何事情是不正确的。
You can't dynamically add fields to a record.
我没有动态地向记录添加字段,我正在创建一个与现有记录匹配的新记录,除了它有一个 id
字段值为 123
.
That's just not a thing records do, probably because it would be really awkward if a already had an id field.
这似乎是您推理的实际内容,但我认为它不是很有说服力。为什么那会很尴尬?以这种方式工作似乎是迄今为止最明显的工作方式?
If this isn't what you want, then it seems this is a case of the XY problem
顺便说一句,但每次我在 Elm 的类型系统中遇到 annoyances/weaknesses 都是我的错,而不是 Elms。
如果它是一条没有任何特定字段的记录,那么无论如何您都无法用它做任何类似记录的事情,因此能够表达它似乎没有用。
您不能向记录动态添加字段。这不是记录所做的事情,可能是因为如果 a
已经有一个 id
字段会很尴尬。所以为了分配 id
你需要知道记录有一个 id
字段。因此函数的正确类型是:
func : {a | id : Int} -> {a | id : Int}
如果这不是您想要的,那么这似乎是 the XY problem
的情况不,Elm 没有办法让类型注释在不指定任何字段的情况下指示类型是记录。但是,即使没有类型注释,Elm 也没有语法来执行您想要的操作。 { a | id = 123 }
是 record update 语法,它不支持向记录添加字段(并且,从 Elm 0.19 开始,也不支持更改字段类型)
据我所知,Elm 没有允许您生成带有附加字段的记录副本的语法。
以上答案是正确的,而且更符合地道,但我认为您可以通过使用新字段定义记录的类型别名来完成您想要的。当然,您必须为所有可能的记录类型定义联合类型 C
。
type alias A = { a : String }
type alias B = { a : Int }
type C = Foo A
| Bar B
type alias D = { a : C, d : Int }
fn : C -> Int -> D
fn a y = D a y