purescript - 在 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
基本上,我想知道在这种情况下解码像 Attributes 这样的 Sum 类型的正确方法是什么
解决方案
(..) But the following does not work
TLDR; This should work:
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"
Let's jump into compiler shoes for a moment and try to infer the value
type.
In the monadic block in decodeJson
there is a call to getField
:
value <- getField obj "value"
getField
is polymorphic on its return type:
getField :: forall a. DecodeJson a => Object Json -> String -> Either String a
So from this call alone we are not able to guess the type of the value
. We need some more information / context.
But luckily few lines below we can find a usage of value
which gives us some solution:
"text-align" -> Right $ TextAlignment value
So for sure our value
has to be typed as TextAlign
because TextAlignment
constructor expects such a parameter.
But wait... just line underneath there is another usage of value
:
"font-size" -> Right $ TextScale value
and here we have a problem because this tells us that value
has type String
and... TextAlign
at the same time...
We have no other choice than tell the World about our discovery:
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
Your approach is OK to me. It gives you full control over coding / decoding process. It can be error prone though...
You can give a try and use fully generic solution like
purescript-argounaut-generic
.You can also try different generic approach and use
purescript-simple-json
. I wasn't able to find example for generic sum handling - here is only enum like type encoded / decoded: https://www.reddit.com/r/purescript/comments/7b5y7q/some_extra_examples_of_simplejson_usage/. You can always ask Justin Woo for suggestions - he is really responsive author :-)I haven't used
purescript-codec-argonaut
yet but it should help you minimize some duplication related to coding and decoding definitions. With this approach you are still responsible for defining everything by hand I think.Here is interesting post, which I think is mostly relevant if you do not have PureScript on both ends of the wire (consumer and producer) by @garyb about downsides of generic codecs: http://code.slipthrough.net/2018/03/13/thoughts-on-typeclass-codecs/
Do you have PureScript on both ends of the wire?
推荐阅读
- webgl - 在 WebGL 中实现阴影的问题
- r - data.table:通过具有多个分组变量的组选择具有最大值的行
- javascript - django链接表行查看
- node.js - TypeError:message.channel.sendMessage 不是函数
- sql - 获取每个月数据的差异
- azure-cosmosdb - Cosmos DB 查询同一字段必须有两个值的文档
- beautifulsoup - 使用 BeautifulSoup 抓取论坛并以表格形式显示
- javascript - 检查是否在 JEST 中调用了 window.location.reload
- visual-studio - 如何在 vtk 窗口中读取和显示 .csv 文件
- c++ - const 函数上的 std::function 不完整类型