在纯脚本中解码联合类型
Decoding Union types in purescript
我正在使用 purescript-agronauth 库将以下类型手动编码和解码为 json 并返回。但是下面的不行
data Attributes
= TextAlignment TextAlign
| TextScale String
| LineHeight String
instance encodeAttributes :: EncodeJson Attributes where
encodeJson r =
case r of
(TextAlignment p) ->
"key" := (fromString "text-align")
~> "value" := p
(TextScale p) ->
"key" := (fromString "font-size")
~> "value" := p
(LineHeight p) ->
"key" := (fromString "line-height")
~> "value" := p
instance decodeElementAttributes :: DecodeJson ElementAttributes where
decodeJson json = do
obj <- decodeJson json
key <- getField obj "key"
value <- getField obj "value"
case key of
"text-align" -> Right $ TextAlignment value
"font-size" -> Right $ TextScale value
"line-height" -> Right $ LineHeight value
_ -> Left "Unkown element property"
data TextAlign
= LeftAlign
| RightAlign
| CenterAlign
| Justify
instance encodeTextAlign :: EncodeJson TextAlign where
encodeJson r =
case r of
LeftAlign -> fromString "left"
RightAlign -> fromString "right"
CenterAlign -> fromString "center"
Justify -> fromString "justify"
instance decodeTextAlign :: DecodeJson TextAlign where
decodeJson obj = do
case toString obj of
Just "left" -> Right LeftAlign
Just "right" -> Right RightAlign
Just "center" -> Right CenterAlign
Just "justify" -> Right Justify
Just _ -> Left "Unknown alignment"
Nothing -> Left "Unknown alignment"
这给出了以下错误
Could not match type
TextAlign
with type
String
while checking that type t0
is at least as general as type String
while checking that expression value
has type String
in value declaration decodeElementAttributes
where t0 is an unknown type
基本上,我想知道在这种情况下解码 Sum 类型(如属性)的正确方法是什么
(..) But the following does not work
TLDR;这应该有效:
instance decodeElementAttributes :: DecodeJson Attributes where
decodeJson json = do
obj <- decodeJson json
key <- getField obj "key"
case key of
"text-align" -> TextAlignment <$> getField obj "value"
"font-size" -> TextScale <$> getField obj "value"
"line-height" -> LineHeight <$> getField obj "value"
_ -> Left "Unkown element property"
让我们试一下编译器并尝试推断 value
类型。
在 decodeJson
的 monadic 块中调用了 getField
:
value <- getField obj "value"
getField
在其 return 类型上是多态的:
getField :: forall a. DecodeJson a => Object Json -> String -> Either String a
因此仅从这个调用我们无法猜测 value
的类型。我们需要更多信息/上下文。
但幸运的是,下面几行我们可以找到 value
的用法,这为我们提供了一些解决方案:
"text-align" -> Right $ TextAlignment value
所以可以肯定我们的 value
必须键入 TextAlign
因为 TextAlignment
构造函数需要这样的参数。
但是等等...下面一行还有 value
的另一种用法:
"font-size" -> Right $ TextScale value
这里我们遇到了一个问题,因为这告诉我们 value
的类型是 String
并且... TextAlign
同时...
我们别无选择,只能告诉世界我们的发现:
Could not match type
TextAlign
with type
String
Basically, I would like to know what would be the proper way to decode a Sum type like Attributes in this case
你的方法我觉得可以。它使您可以完全控制编码/解码过程。虽然它可能容易出错...
您可以尝试使用完全通用的解决方案,例如 purescript-argounaut-generic
。
您也可以尝试不同的通用方法并使用 purescript-simple-json
。我无法找到通用总和处理的示例 - 这里只是像编码/解码类型这样的枚举:https://www.reddit.com/r/purescript/comments/7b5y7q/some_extra_examples_of_simplejson_usage/。您可以随时向 Justin Woo 寻求建议 - 他是一位非常有求必应的作者:-)
我还没有使用过 purescript-codec-argonaut
但它应该可以帮助您减少与编码和解码定义相关的一些重复。使用这种方法,我认为您仍然需要手动定义所有内容。
这里很有趣 post,如果你在线路的两端(消费者和生产者)都没有 PureScript,我认为这是最相关的@garyb 关于通用编解码器的缺点: http://code.slipthrough.net/2018/03/13/thoughts-on-typeclass-codecs/
你的电线两端都有 PureScript 吗?
我正在使用 purescript-agronauth 库将以下类型手动编码和解码为 json 并返回。但是下面的不行
data Attributes
= TextAlignment TextAlign
| TextScale String
| LineHeight String
instance encodeAttributes :: EncodeJson Attributes where
encodeJson r =
case r of
(TextAlignment p) ->
"key" := (fromString "text-align")
~> "value" := p
(TextScale p) ->
"key" := (fromString "font-size")
~> "value" := p
(LineHeight p) ->
"key" := (fromString "line-height")
~> "value" := p
instance decodeElementAttributes :: DecodeJson ElementAttributes where
decodeJson json = do
obj <- decodeJson json
key <- getField obj "key"
value <- getField obj "value"
case key of
"text-align" -> Right $ TextAlignment value
"font-size" -> Right $ TextScale value
"line-height" -> Right $ LineHeight value
_ -> Left "Unkown element property"
data TextAlign
= LeftAlign
| RightAlign
| CenterAlign
| Justify
instance encodeTextAlign :: EncodeJson TextAlign where
encodeJson r =
case r of
LeftAlign -> fromString "left"
RightAlign -> fromString "right"
CenterAlign -> fromString "center"
Justify -> fromString "justify"
instance decodeTextAlign :: DecodeJson TextAlign where
decodeJson obj = do
case toString obj of
Just "left" -> Right LeftAlign
Just "right" -> Right RightAlign
Just "center" -> Right CenterAlign
Just "justify" -> Right Justify
Just _ -> Left "Unknown alignment"
Nothing -> Left "Unknown alignment"
这给出了以下错误
Could not match type
TextAlign
with type
String
while checking that type t0
is at least as general as type String
while checking that expression value
has type String
in value declaration decodeElementAttributes
where t0 is an unknown type
基本上,我想知道在这种情况下解码 Sum 类型(如属性)的正确方法是什么
(..) But the following does not work
TLDR;这应该有效:
instance decodeElementAttributes :: DecodeJson Attributes where
decodeJson json = do
obj <- decodeJson json
key <- getField obj "key"
case key of
"text-align" -> TextAlignment <$> getField obj "value"
"font-size" -> TextScale <$> getField obj "value"
"line-height" -> LineHeight <$> getField obj "value"
_ -> Left "Unkown element property"
让我们试一下编译器并尝试推断 value
类型。
在 decodeJson
的 monadic 块中调用了 getField
:
value <- getField obj "value"
getField
在其 return 类型上是多态的:
getField :: forall a. DecodeJson a => Object Json -> String -> Either String a
因此仅从这个调用我们无法猜测 value
的类型。我们需要更多信息/上下文。
但幸运的是,下面几行我们可以找到 value
的用法,这为我们提供了一些解决方案:
"text-align" -> Right $ TextAlignment value
所以可以肯定我们的 value
必须键入 TextAlign
因为 TextAlignment
构造函数需要这样的参数。
但是等等...下面一行还有 value
的另一种用法:
"font-size" -> Right $ TextScale value
这里我们遇到了一个问题,因为这告诉我们 value
的类型是 String
并且... TextAlign
同时...
我们别无选择,只能告诉世界我们的发现:
Could not match type
TextAlign
with type
String
Basically, I would like to know what would be the proper way to decode a Sum type like Attributes in this case
你的方法我觉得可以。它使您可以完全控制编码/解码过程。虽然它可能容易出错...
您可以尝试使用完全通用的解决方案,例如
purescript-argounaut-generic
。您也可以尝试不同的通用方法并使用
purescript-simple-json
。我无法找到通用总和处理的示例 - 这里只是像编码/解码类型这样的枚举:https://www.reddit.com/r/purescript/comments/7b5y7q/some_extra_examples_of_simplejson_usage/。您可以随时向 Justin Woo 寻求建议 - 他是一位非常有求必应的作者:-)我还没有使用过
purescript-codec-argonaut
但它应该可以帮助您减少与编码和解码定义相关的一些重复。使用这种方法,我认为您仍然需要手动定义所有内容。这里很有趣 post,如果你在线路的两端(消费者和生产者)都没有 PureScript,我认为这是最相关的@garyb 关于通用编解码器的缺点: http://code.slipthrough.net/2018/03/13/thoughts-on-typeclass-codecs/
你的电线两端都有 PureScript 吗?