Elm:如何 Json 使用单个 TypeConstructor 解码联合类型?
Elm: How to Json decode a Union Type with a single TypeConstructor?
如以下代码所示,解码 UserAlias 很容易,但是当我尝试解码 UserType 时,即用 D.map2 UserType
替换 D.map2 UserAlias
编译器大声喊叫。如何修复此编译器错误?
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.
如何解决这个错误,请帮忙!
基本上我不再希望使用类型别名,而只希望使用用户 UserType,这样我就可以隐藏内部记录结构,并在不破坏 public API.
的情况下重构它
谢谢。
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
比 Chad 的回答更直接的方法是在 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
中的模式匹配。不过,就性能而言,它可能不会给你带来太多好处!
如果你觉得更简洁一点,这也可以写成无点风格:
userDecoder = D.map2 (((<<) UserType ) << UserAlias)
(D.field "name" D.string)
(D.field "age" D.int)
如以下代码所示,解码 UserAlias 很容易,但是当我尝试解码 UserType 时,即用 D.map2 UserType
替换 D.map2 UserAlias
编译器大声喊叫。如何修复此编译器错误?
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.
如何解决这个错误,请帮忙!
基本上我不再希望使用类型别名,而只希望使用用户 UserType,这样我就可以隐藏内部记录结构,并在不破坏 public API.
的情况下重构它谢谢。
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
比 Chad 的回答更直接的方法是在 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
中的模式匹配。不过,就性能而言,它可能不会给你带来太多好处!
如果你觉得更简洁一点,这也可以写成无点风格:
userDecoder = D.map2 (((<<) UserType ) << UserAlias)
(D.field "name" D.string)
(D.field "age" D.int)