Как инициализировать значение, основанное на псевдониме рекурсивного типа?
Как инициализировать значение, основанное на псевдониме рекурсивного типа?
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 └─────┘
Я ссылаюсь на эту документацию. Однако я не понимаю, почему я все еще получаю ошибку компилятора.
Приложение:
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 ответа
Ваш код синтаксически правильный, и до версии Elm 0.18 он компилировался бы. Но когда вы запустите программу, вы окажетесь либо в переполнении стека, либо в бесконечном цикле (из-за оптимизации рекурсии хвостового вызова), либо в исключительной ситуации времени выполнения из-за ошибки компилятора, которая с тех пор была исправлена.
Подумайте, через что должна пройти среда выполнения, чтобы расширить contentProvider1
:
- расширять
contentProvider1
, который имеет ссылку наcontentProvider2
- расширять
contentProvider2
, который имеет ссылку наcontentProvider1
- расширять
contentProvider1
, который имеет ссылку наcontentProvider2
- и так до бесконечности
Что вы испытываете, так это супер полезный компилятор Elm, спасающий вас от кода, который в любом случае не сработал бы. Все еще возможно написать функцию без остановки ( и всегда будет), но компилятор Elm теперь проверяет некоторые распространенные случаи, которые в противном случае могли бы сработать во время выполнения.
Вот некоторая документация, которая более подробно объясняет причину этой ошибки компилятора.
contentProvider2 и contentProvider3 должны быть определены, как сказал Чад Гилберт, но проблема здесь не в вашем взаимно рекурсивном псевдониме типа, а в круговой ссылке на значение, которая невозможна. Вот упрощенный пример, который компилируется:
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 [])