榆树是否允许循环引用?

时间:2016-10-04 16:18:05

标签: elm

假设有两种数据类型:

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并创建链接的数据结构?我不确定如何使用纯粹的不可变数据结构,或者如果可能的话。

2 个答案:

答案 0 :(得分:5)

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个引用。在上面的数据类型中,每个玩家必须有一个团队。如果team是一个可选字段,我将定义如下:

type alias Player = 
  { name : String
  , teamID : Maybe ID
  }

对于ListString类型,您实际上并不需要Maybe类型。使用[](空列表)和""(空字符串)可以更轻松地处理空状态。

PS:另一个假设是您有特定的需要将团队成员列表存储在模型的每个团队中。因为严格来说你不需要:玩家列表已经拥有了查找哪些玩家(如果有的话)属于X队所需的所有数据。 请注意,如果你保持双向参考,这是很多工作(并且可能导致讨厌的错误):如果玩家切换团队,你需要更新3条记录(1名玩家+ 2个团队记录)。

答案 1 :(得分:4)

使用不可变数据结构,无法创建以某种循环方式相互引用的完全耦合的值层次结构。

其核心问题可以通过几个步骤来说明:

  1. 为其父字段
  2. 创建一个Nothing的子项
  3. 创建指向孩子的父母
  4. 将孩子更新为指向父母
  5. 当你有不可变的数据结构时,3号是不可能的,因为&#34;修改&#34;子项意味着您创建一个新值,而父项仍然指向该旧值。如果您随后更新了父级,那么您必须再次更新孩子,无限期。

    我建议使用Dict玩家和小组,并按其各自的ID编制索引以供查找。