2016-11-27 2 views
2

Wie im folgenden Code zu sehen ist, ist es einfach, UserAlias ​​zu decodieren, aber der Moment, in dem ich versuche, UserType zu decodieren, d. H. Ersetzen D.map2 UserAlias durch D.map2 UserType Compiler schreit laut. Wie behebe ich diesen Compilerfehler?Elm: Wie zu Json decode einen Union Type mit einem einzigen TypeConstructor?

import Json.Decode as D 
import Html exposing (..) 
import Result as R 

type UserType = UserType {name:String, age:Int} 

type alias UserAlias = {name:String, age:Int} 


userDecoder = D.map2 UserAlias 
       (D.field "name" D.string) 
       (D.field "age" D.int) 


decodeUser json = D.decodeString userDecoder json 


json = """ 
    { "name": "Bob", "age": 40 } 
""" 


main = div [] [(text << toString << decodeUser) json] 

Der obige Code funktioniert gut. Jetzt ersetzen D.map2 UserAlias mit D.map2 UserType

Und Compiler ruft

Detected errors in 1 module. 
==================================== ERRORS ==================================== 



-- TYPE MISMATCH --------------------------------------------------------------- 

The 2nd argument to function `map2` is causing a mismatch. 

13|    D.map2 UserType 
14|>    (D.field "name" D.string) 
15|     (D.field "age" D.int) 

Function `map2` is expecting the 2nd argument to be: 

    D.Decoder { age : Int, name : String } 

But it is: 

    D.Decoder String 

Hint: I always figure out the type of arguments from left to right. If an 
argument is acceptable when I check it, I assume it is "correct" in subsequent 
checks. So the problem may actually be in how previous arguments interact with 
the 2nd. 



-- TYPE MISMATCH --------------------------------------------------------------- 

The 1st argument to function `map2` is causing a mismatch. 

13|>    D.map2 UserType 
14|     (D.field "name" D.string) 
15|     (D.field "age" D.int) 

Function `map2` is expecting the 1st argument to be: 

    { age : Int, name : String } -> b -> UserType 

But it is: 

    { age : Int, name : String } -> UserType 

Hint: It looks like a function needs 1 more argument. 

Wie kann ich diesen Fehler zu beheben, bitte helfen!

Grundsätzlich möchte ich nicht mehr Typ Alias ​​und nur Benutzer UserType verwenden, so dass ich interne Datensatzstruktur ausblenden und umgestalten kann, ohne die öffentliche API zu brechen.

danke.

Antwort

3

Der UserType Konstruktor nimmt einen einzelnen Parameter von UserAlias, so können wir einfach Json.Decode.map in Ihrem vorhandenen Decoder verwenden, um die UserAlias Wert zu nehmen und einen Decoder für UserType wie dieses Konstrukt:

userDecoder : D.Decoder UserType 
userDecoder = D.map2 UserAlias 
       (D.field "name" D.string) 
       (D.field "age" D.int) 
       |> D.map UserType 
+0

Vielen Dank, Sie sind ein Lebensretter wie immer: D Jetzt kann ich endlich Typ verwenden Konstruktoren, um die Implementierungsstruktur zu verbergen. – Jigar

+0

Aber dies verwendet immer noch Typ-Alias, OP war auf der Suche nach einer Lösung ohne Typ Alias ​​ –

3

Eine etwas direkte Art und Weise als Tschads Antwort wäre, dies zu tun in der map2 Funktion:

userDecoder : D.Decoder UserType 
userDecoder = D.map2 (\name age -> UserType <| UserAlias name age) 
       (D.field "name" D.string) 
       (D.field "age" D.int) 

Dadurch wird die Musterübereinstimmung in der zweiten map vermieden. Es wird Ihnen hier wahrscheinlich nicht viel an Leistung abverlangen!

Wenn Sie fühlen sich ein wenig mehr terse zu sein, kann dies auch in einem pointfree Stil geschrieben werden:

userDecoder = D.map2 (((<<) UserType) << UserAlias) 
       (D.field "name" D.string) 
       (D.field "age" D.int) 
+0

Danke, ich habe Ihre Antwort sehr geschätzt, da es mir hilft, besser zu verstehen, wie diese APIs funktionieren. Hoffentlich kann ich solche Muster in meinem Code lernen und annehmen. Obwohl für praktische Zwecke werde ich Chad's Antwort verwenden;) – Jigar