2016-11-27 11 views
2

Как видно из следующего кода, легко декодировать UserAlias, но в тот момент, когда я пытаюсь декодировать UserType i.e. Заменить D.map2 UserAlias с помощью D.map2 UserType Компилятор громко кричит. Как исправить эту ошибку компилятора?Elm: Как Json расшифровывает тип Union с одним 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] 

Над кодом работает отлично. Теперь замените D.map2 UserAlias с D.map2 UserType

и составитель взывает

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. 

Как исправить эту ошибку, пожалуйста, помогите!

В основном я nolonger хочу использовать псевдоним типа и только пользовательский тип UserType, чтобы я мог скрывать внутреннюю структуру записи и реорганизовывать его, не нарушая публичный API.

спасибо.

ответ

3

UserType конструктор принимает один параметр UserAlias, поэтому мы можем просто использовать Json.Decode.map внутри существующего декодера принимать значение UserAlias и построить декодер для UserType так:

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

Спасибо большое, Вы спасатель жизни, как всегда: D Теперь я могу, наконец, использовать тип Конструкторы скрывают структуру реализации. – Jigar

+0

Но это все еще использует псевдоним типа, OP искал решение без псевдонима типа –

3

Чуть более прямой ответ, чем ответ Чада, должен был бы сделать это в функции map2:

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

Это позволит избежать совпадения шаблонов во втором map. Это, вероятно, не собирается покупать вас с точки зрения производительности здесь!

Если вы чувствуете, как быть немного более лаконична, это также может быть написана в стиле pointfree:

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

Спасибо, я очень оценил ваш ответ, так как он помогает мне лучше понять, как работают эти API. Надеюсь, я смогу изучить и использовать такие шаблоны в своем коде. Хотя для практических целей я буду использовать Ответ Чада;) – Jigar