2016-10-04 70 views
4

假设两种数据类型: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并创建链接的数据结构?我不确定如何用纯粹不可变的数据结构来做到这一点,或者如果可能的话。

回答

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 
    } 

UPDATE:你还别说在你的问题null引用。在上面的数据类型中,每个玩家必须有一个团队。如果团队是一个可选字段,我将定义如下:

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

对于ListString类型,你并不真正需要的Maybe类型。 [](空列表)和""(空字符串)对于那些空状态更容易。

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

+0

顺便说一句:处理带有'Dict'和'ID'的循环引用也是@ChadGilbert在他的回答中提到的。 – wintvelt

4

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

在它的核心,这个问题可以通过几个步骤来说明:

  1. 其父场
  2. 创建指向在孩子
  3. 更新孩子父母创建Nothing孩子指向父代

当你拥有不可变的数据结构时,数字3是不可能的,因为对子代的“修改”意味着你创建了一个新的值,家长仍然会指出那个旧价值。如果您随后更新了家长,那么您必须再次更新孩子,无限次。

我会推荐使用玩家和团队的Dict,这些玩家和团队都会根据各自的ID进行索引以进行查找。

+0

如果你真的想要一个像你所描述的结构,队员和队员可以在浅层次相互引用,那么可以用一些“Json.andThen”杂技。我很好奇,所以我继续前进,掀起了一个如何做到这一点的快速和肮脏的例子,[如果你有兴趣](https://gist.github.com/freakingawesome/82109ca1b9eba8dbdef1fbd43293699c)。 –