2017-09-15 3 views
0

Comment implémenter un décodeur qui s'appelle lui-même en raison de l'un de ses champs ayant le même type?Comment implémenter un décodeur qui s'appelle lui-même en raison de l'un de ses champs ayant le même type?

providerDecoder : Decoder JsonProvider 
providerDecoder = 
    Decode.map6 JsonProvider 
     (field "Profile" profileDecoder) 
     (field "Topics" <| Decode.list topicDecoder) 
     (field "Links" <| linksDecoder) 
     (field "RecentLinks" <| Decode.list linkDecoder) 
     (field "Subscriptions" <| Decode.list providerDecoder) 
     (field "Followers" <| Decode.list providerDecoder) 

Les lignes suivantes sont à l'origine des problèmes:

(field "Subscriptions" <| Decode.list providerDecoder) 
(field "Followers" <| Decode.list providerDecoder) 

providerDecoder est directement défini en termes de lui-même, ce qui provoque une infinie

En conclusion, je ne sais pas comment pour résoudre cette erreur tout en préservant le type JsonProvider.

Annexe:

type JsonProvider 
    = JsonProvider 
     { profile : JsonProfile 
     , topics : List JsonTopic 
     , links : JsonLinks 
     , recentLinks : List JsonLink 
     , subscriptions : List JsonProvider 
     , followers : List JsonProvider 
     } 

Répondre

3

Lorsque vous écrivez des décodeurs JSON récursives, il faut généralement compter sur Json.Decode.lazy. Vous pouvez écrire ces deux lignes comme ceci:

(field "Subscriptions" <| Decode.list (Decode.lazy (\_ -> providerDecoder))) 
(field "Followers" <| Decode.list (Decode.lazy (\_ -> providerDecoder))) 

Une fois que vous changez que vous verrez un autre message d'erreur pop-up sur les types qui ne correspondent pas, et c'est parce que vous utilisez un seul type d'union constructeur qui a un enregistrement en tant qu'argument (qui est nécessaire lors de l'écriture des types d'enregistrements récursifs). Dans ce cas, je sépare habituellement le type de constructeur et enregistrer comme ceci:

type JsonProvider 
    = JsonProvider JsonProviderFields 

type alias JsonProviderFields = 
    { profile : JsonProfile 
    , topics : List JsonTopic 
    , links : JsonLinks 
    , recentLinks : List JsonLink 
    , subscriptions : List JsonProvider 
    , followers : List JsonProvider 
    } 

Maintenant, vous pouvez réécrire le décodeur de fournisseur d'abord décoder l'enregistrement JsonProviderFields, la carte puis à un JsonProvider:

providerDecoder : Decoder JsonProvider 
providerDecoder = 
    Decode.map6 JsonProviderFields 
     (field "Profile" profileDecoder) 
     (field "Topics" <| Decode.list topicDecoder) 
     (field "Links" <| linksDecoder) 
     (field "RecentLinks" <| Decode.list linkDecoder) 
     (field "Subscriptions" <| Decode.list (Decode.lazy (\_ -> providerDecoder))) 
     (field "Followers" <| Decode.list (Decode.lazy (\_ -> providerDecoder))) 
     |> Decode.map JsonProvider