如何根据递归类型别名初始化值?

时间:2017-07-08 18:41:33

标签: elm

如何基于递归类型别名初始化值?

type alias ContentProvider =
    { profile : Profile
    , topics : List Topic
    , links : Links
    , subscribers : Subscribers
    }


type Subscribers
    = Subscribers (List ContentProvider)

我尝试初始化值失败:

contentProvider1 : ContentProvider
contentProvider1 =
    ContentProvider profile1 topics contentProvider1Links (Subscribers [ contentProvider2, contentProvider3 ])

请注意,最后一个参数导致错误:

(Subscribers [ contentProvider2, contentProvider3 ])
  

contentProvider1以偷偷摸摸的方式定义,   导致无限循环。 - 以下定义直接取决于   在彼此:

┌─────┐
│    contentProvider1
│     ↓
│    contentProvider2
│     ↓
│    contentProvider3
└─────┘

我引用了此documentation。但是,我不明白为什么我仍然遇到编译器错误。

附录

contentProvider1 : ContentProvider
contentProvider1 =
    ContentProvider profile1 topics contentProvider1Links (Subscribers [ contentProvider2 ])


contentProvider2 : ContentProvider
contentProvider2 =
    ContentProvider profile2 topics contentProvider2Links (Subscribers [ contentProvider1, contentProvider3 ])


contentProvider3 : ContentProvider
contentProvider3 =
    ContentProvider profile3 topics contentProvider3Links (Subscribers [ contentProvider1, contentProvider2 ])

2 个答案:

答案 0 :(得分:3)

你的代码在语法上是正确的,在Elm 0.18之前,它会被编译。但是当你运行程序时,你最终会陷入堆栈溢出,无限循环(因为尾部调用递归优化)或运行时异常because of a compiler bug that has since been fixed

考虑运行时扩展contentProvider1所需的内容:

  1. 展开contentProvider1,其中引用了contentProvider2
  2. 展开contentProvider2,其中引用了contentProvider1
  3. 展开contentProvider1,其中引用了contentProvider2
  4. 依此类推,永恒
  5. 您所遇到的是Elm的超级有用的编译器,可以保存您无法使用的代码。仍然可以编写一个非暂停函数(and always will be),但是Elm的编译器现在会检查一些在运行时会爆炸的常见情况。

    Here is some documentation that more thoroughly explains the reasoning behind this compiler error

答案 1 :(得分:1)

contentProvider2和contentProvider3需要像Chad Gilbert那样定义,但这里的问题不是你的相互递归类型别名,而是circular value reference that is not possible。以下是编译的简化示例:

type alias ContentProvider =
    { profile : String
    , topics : List String
    , links : String
    , subscribers : Subscribers
    }

type Subscribers = 
    Subscribers (List ContentProvider)

contentProvider1 : ContentProvider
contentProvider1 =
    ContentProvider "profile" ["art", "science"] "test" (Subscribers [contentProvider2])

contentProvider2 : ContentProvider
contentProvider2 =
    ContentProvider "profile" ["art", "science"] "test" (Subscribers [])