我有一个用GADT创建的数据结构,我想使用aeson解析一些json到这个GADT。但是类型检查程序抱怨说,在所有情况下都只能创建GADT的一个构造函数。参见此示例:
data Foo = Hello | World
data SFoo :: Foo -> Type where
SHello :: SFoo 'Hello
SWorld :: SFoo 'World
instance FromJSON (SFoo a) where
parseJSON = withText "Foo" \case
"hello" -> pure SHello
"world" -> pure SWorld因此,我希望能够将"hello“字符串解析为SHello,将"world”字符串解析为SWorld。类型检查器会出现以下错误:
• Couldn't match type ‘'World’ with ‘'Hello’
Expected type: Parser (SFoo 'Hello)
Actual type: Parser (SFoo 'World)
• In the expression: pure SWorld
In a case alternative: "world" -> pure SWorld
In the second argument of ‘withText’, namely
‘\case
"hello" -> pure SHello
"world" -> pure SWorld’如何将json解析为这样的GADT结构?
发布于 2020-07-15 13:46:36
这
instance FromJSON (SFoo a) where不会飞。你会得到
parseJSON :: forall a. Value -> Parser (SFoo a)这意味着调用方可以选择他们想要的a,而parseJSON并不控制从JSON解析a。相反,你想
data SomeFoo = forall a. SomeFoo (SFoo a)
instance FromJSON SomeFoo where
parseJSON = withText "Foo" \case
"hello" -> pure $ SomeFoo SHello
"world" -> pure $ SomeFoo SWorld
_ -> fail "not a Foo" -- aeson note: without this you get crashes!现在在哪里
fromJSON :: Value -> Result SomeFoo不告诉您它将以其类型返回SFoo的哪个分支。SomeFoo现在是一对a :: Foo类型和SFoo a值。fromJSON现在负责解析整个对,因此它控制返回的类型和值。当您使用它并在SomeFoo上匹配时,这将告诉您必须处理哪种类型:
example :: Value -> IO ()
example x = case fromJSON x of
Error _ -> return ()
Success (SomeFoo x) -> -- know x :: SFoo a where a is a type extracted from the match; don't know anything about a yet
case x of
SHello -> {- now know a ~ Hello -} return ()
SWorld -> {- now know a ~ World -} return ()注意,SomeFoo基本上是与Foo同构的。你还是写信吧
instance FromJSON Foo where ..然后
someFoo :: Foo -> SomeFoo
someFoo Hello = SomeFoo SHello
someFoo World = SomeFoo SWorld
instance FromJSON SomeFoo where parseJSON = fmap someFoo . parseJSON请注意,您可以编写以下两个实例:
instance FromJSON (SFoo Hello) where
parseJSON = withText "SFoo Hello" \case
"hello" -> pure SHello
_ -> fail "not an SFoo Hello"
instance FromJSON (SFoo World) where
parseJSON = withText "SFoo World" \case
"world" -> pure SWorld
_ -> fail "not an SFoo World"...but --它们不是特别有用,只是作为另一种方式编写FromJSON SomeFoo
instance FromJSON SomeFoo where
parseJSON x = prependFailure "SomeFoo: " $
SomeFoo @Hello <$> parseJSON x <|> SomeFoo @World <$> parseJSON xhttps://stackoverflow.com/questions/62915610
复制相似问题