Elm 是否允许循环引用?
Does Elm allow circular references?
假设有两种数据类型:
type alias Player =
{ name : String
, team : Team
}
type alias Team =
{ name : String
, players : List Player
}
还有这个JSON:
{
"players": [
{ "id": 100, "name": "Sam Bradford", "teamId": 200 },
{ "id": 101, "name": "Kyle Rudolph", "teamId": 200 },
{ "id": 102, "name": "Matthew Stafford", "teamId": 201 },
{ "id": 103, "name": "Marvin Jones Jr.", "teamId": 201 },
{ "id": 104, "name": "Golden Tate", "teamId": 201 },
],
"teams": [
{ "id": 200, "name": "Minnesota Vikings" },
{ "id": 201, "name": "Detroit Lions" },
]
}
很明显,这个 JSON 可以解码为非空链接对象,这可以由 JSON 解码器在解码数据时确定。有没有办法解码这个 JSON 并创建链接的数据结构?我不确定如何使用纯粹不可变的数据结构来做到这一点,或者是否可能。
使用不可变数据结构,不可能创建以某种循环方式相互引用的完全耦合的值层次结构。
问题的核心可以通过几个步骤来说明:
- 创建一个父字段
Nothing
的子字段
- 创建指向子项的父项
- 更新子项以指向父项
当您拥有不可变的数据结构时,数字 3 是不可能的,因为子节点的 "modification" 意味着您创建了一个新值,而父节点仍将指向该旧值。如果您随后更新了父项,那么您将不得不再次更新子项,如此循环往复。
我建议使用 Dict
球员和球队,由他们各自的 ID 索引以供查找。
Elm中对递归数据类型有很好的解释here。
如果您尝试编译您的数据类型,您会收到以下错误:
-- ALIAS PROBLEM ---------------------------------------------------------------
This type alias is part of a mutually recursive set of type aliases.
4|>type alias Player =
5|> { name : String
6|> , team : Team
7|> }
The following type aliases are mutually recursive:
┌─────┐
│ V
│ Player
│ │
│ V
│ Team
└─────┘
You need to convert at least one `type alias` into a `type`. This is a kind of
subtle distinction, so definitely read up on this before you make a fix:
<https://github.com/elm-lang/elm-compiler/blob/0.17.0/hints/recursive-alias.md>
你也可以换个方式处理。我更喜欢求助于 ID
参考文献,例如
type alias ID = Int
type alias PlayerList = Dict ID PLayer
type alias TeamList = Dict ID Team
type alias Player =
{ name : String
, teamID : ID
}
type alias Team =
{ name : String
, players : List ID
}
更新:您还在问题中提到了 null
参考资料。在上面的数据类型中,每个玩家必须有一个团队。如果团队是一个可选字段,我将定义如下:
type alias Player =
{ name : String
, teamID : Maybe ID
}
对于 List
和 String
类型,您实际上不需要 Maybe
类型。使用 []
(空列表)和 ""
(空字符串)时,空状态更容易。
PS:另一个假设是您有特定需要在模型的每个团队中存储团队球员列表。因为严格来说你不需要:玩家列表已经包含了找出哪些玩家(如果有的话)属于 X 队所需的所有数据。
请注意,如果您维护 2 向参考,则需要做很多工作(并可能导致严重的错误):如果玩家切换团队,则需要更新 3 条记录(1 位玩家 + 2 条团队记录)。
假设有两种数据类型:
type alias Player =
{ name : String
, team : Team
}
type alias Team =
{ name : String
, players : List Player
}
还有这个JSON:
{
"players": [
{ "id": 100, "name": "Sam Bradford", "teamId": 200 },
{ "id": 101, "name": "Kyle Rudolph", "teamId": 200 },
{ "id": 102, "name": "Matthew Stafford", "teamId": 201 },
{ "id": 103, "name": "Marvin Jones Jr.", "teamId": 201 },
{ "id": 104, "name": "Golden Tate", "teamId": 201 },
],
"teams": [
{ "id": 200, "name": "Minnesota Vikings" },
{ "id": 201, "name": "Detroit Lions" },
]
}
很明显,这个 JSON 可以解码为非空链接对象,这可以由 JSON 解码器在解码数据时确定。有没有办法解码这个 JSON 并创建链接的数据结构?我不确定如何使用纯粹不可变的数据结构来做到这一点,或者是否可能。
使用不可变数据结构,不可能创建以某种循环方式相互引用的完全耦合的值层次结构。
问题的核心可以通过几个步骤来说明:
- 创建一个父字段
Nothing
的子字段 - 创建指向子项的父项
- 更新子项以指向父项
当您拥有不可变的数据结构时,数字 3 是不可能的,因为子节点的 "modification" 意味着您创建了一个新值,而父节点仍将指向该旧值。如果您随后更新了父项,那么您将不得不再次更新子项,如此循环往复。
我建议使用 Dict
球员和球队,由他们各自的 ID 索引以供查找。
Elm中对递归数据类型有很好的解释here。
如果您尝试编译您的数据类型,您会收到以下错误:
-- ALIAS PROBLEM ---------------------------------------------------------------
This type alias is part of a mutually recursive set of type aliases.
4|>type alias Player =
5|> { name : String
6|> , team : Team
7|> }
The following type aliases are mutually recursive:
┌─────┐
│ V
│ Player
│ │
│ V
│ Team
└─────┘
You need to convert at least one `type alias` into a `type`. This is a kind of
subtle distinction, so definitely read up on this before you make a fix:
<https://github.com/elm-lang/elm-compiler/blob/0.17.0/hints/recursive-alias.md>
你也可以换个方式处理。我更喜欢求助于 ID
参考文献,例如
type alias ID = Int
type alias PlayerList = Dict ID PLayer
type alias TeamList = Dict ID Team
type alias Player =
{ name : String
, teamID : ID
}
type alias Team =
{ name : String
, players : List ID
}
更新:您还在问题中提到了 null
参考资料。在上面的数据类型中,每个玩家必须有一个团队。如果团队是一个可选字段,我将定义如下:
type alias Player =
{ name : String
, teamID : Maybe ID
}
对于 List
和 String
类型,您实际上不需要 Maybe
类型。使用 []
(空列表)和 ""
(空字符串)时,空状态更容易。
PS:另一个假设是您有特定需要在模型的每个团队中存储团队球员列表。因为严格来说你不需要:玩家列表已经包含了找出哪些玩家(如果有的话)属于 X 队所需的所有数据。 请注意,如果您维护 2 向参考,则需要做很多工作(并可能导致严重的错误):如果玩家切换团队,则需要更新 3 条记录(1 位玩家 + 2 条团队记录)。