解码purescript中的联合类型

时间:2018-11-11 19:31:39

标签: 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类型的正确方法是什么

1 个答案:

答案 0 :(得分:1)

  

(..)但以下操作无效

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在其返回类型上是多态的:

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
  

基本上,我想知道在这种情况下解码诸如属性之类的Sum类型的正确方法是什么

  • 您的方法对我来说还可以。它使您可以完全控制编码/解码过程。但这可能很容易出错...

  • 您可以尝试使用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,但是它应该可以帮助您最大程度地减少与编码和解码定义有关的重复。我认为,采用这种方法,您仍然需要手动定义所有内容。

  • 这是一个有趣的帖子,如果您在@garyb的两端(消费者和生产者)都没有PureScript关于通用编解码器的缺点,我认为这是最相关的:http://code.slipthrough.net/2018/03/13/thoughts-on-typeclass-codecs/

导线的两端是否都装有PureScript?