gpt4 book ai didi

haskell - 解析json时构造GADT

转载 作者:行者123 更新时间:2023-12-04 02:33:38 25 4
gpt4 key购买 nike

我有一个用 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和“世界”字符串到 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 结构?

最佳答案

这个

instance FromJSON (SFoo a) where
不会飞。你会得到
parseJSON :: forall a. Value -> Parser (SFoo a)
这意味着调用者可以选择哪个 a他们想要,和 parseJSON无法控制解析 a来自 JSON。相反,你想要
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值(value)。 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"
...但它们并不是特别有用,除非作为另一种写法 FromJSON SomeFoo :
instance FromJSON SomeFoo where
parseJSON x = prependFailure "SomeFoo: " $
SomeFoo @Hello <$> parseJSON x <|> SomeFoo @World <$> parseJSON x

关于haskell - 解析json时构造GADT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62915610/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com