Haskell:通过 Lens、lens-aeson 和嵌套 JSON 重用 FromJSON 实例

2024-04-18

我一直在使用 Aeson 和镜头包(lens-aeson,从核心镜头包迁移而来),并且一直在努力让它们一起工作。

作为一个玩具示例,我有一个类型:

data Colour = Yellow | Green | Blue

和 FromJSON 实例:

instance FromJSON Colour where
    parseJSON (String s) = return $ case s of
        "blue" -> Blue
        "green" -> Green
        _ -> Yellow
    parseJSON _ = mzero

到目前为止,一切都很好。

现在,假设我有一些嵌套的 JSON 数据,我想从中提取这些数据:

{
    "info": {
        "colour": "yellow"
    },
    /* other props */
}

我不关心其余的,只关心这个“颜色”值。更糟糕的是,假设 JSON 不是特别一致,所以有时我会

{ "item": { "colour": "yellow" } }

和其他时间

{ "random": {"item_colour": "yellow"} }

我希望能够尽可能轻松地获取颜色值,然后使用我的 FromJSON 实例将其理想地解析为颜色。这是一个玩具示例,但数据类型可能具有多个字段等,而不是颜色。

我开始关注lens-aeon的东西,这让我燃起了希望;它允许非常轻松地查看 JSON 结构。例子:

> "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour"
Just (String "yellow")
> "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour" . _String
Just "yellow"

但我找不到一种方法来通过我的 parseJSON 调用来运行它以返回Just Yellow。 parseJSON 看起来很接近,因为它采用正确的类型(可能是至少内部的东西),但之后就崩溃了。理想情况下,我能够执行以下操作之一:

> "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour" . _ParseJSON :: Maybe Colour
Just Yellow
> "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour" . _Colour
Just Yellow

我最接近弄清楚的方法是重新编码然后解码上述结果,例如:

> encode $ "{ \"info\": { \"colour\": \"yellow\" } }" ^? key "info" . key "colour"
"\"yellow\""

它返回了我想要的 JSON 编码数据。在更复杂的情况下,如果该数据是对象或数组,我可以运行decode就像我通常会返回更复杂的类型一样,但解码不喜欢不正确的 JSON;没有包含在数组或对象语法中的东西。此外,先解码再编码似乎非常混乱并且性能不佳。

我对镜头和 Aeson 整体来说相当陌生(对于这个问题,还有 Haskell,尽管我已经开始理解诸如 monads/applicatives 之类的东西,但进展缓慢!)。你们打算如何完成这件事?

我的总体动机是,我将处理大量 JSON 数据,但实际上只关心它的片段,因此每次需要从 JSON 中的不同位置获取这些片段时,我宁愿避免声明数据类型,而只是声明我关心的位的类型。

请注意,我使用的是lens-aeson-1和lens-4.4.0.1,而不是aeson-lens,它的工作方式略有不同(它可能与答案相关)!

提前致谢! 詹姆士


您可以使用_JSON http://hackage.haskell.org/package/lens-aeson-1/docs/Data-Aeson-Lens.html#v:_JSON棱镜。你只需要写一个ToJSON实例为Colour:

instance ToJSON Colour where
  toJSON Yellow = String "yellow"
  toJSON Blue   = String "blue"
  toJSON Green  = String "green"

然后你可以像这样使用它:

parseColour :: String -> Maybe Colour
parseColour j = j ^? key "info" . key "colour" . _JSON
-- point-free: parseColor = preview $ key "info" . key "colour" . _JSON

-- In GHCi
λ: parseColour "{ \"info\": { \"colour\": \"yellow\" } }"
Just Yellow
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell:通过 Lens、lens-aeson 和嵌套 JSON 重用 FromJSON 实例 的相关文章

  • 在 Haskell 中将 Maybe Int 转换为 Int

    我正在编写以下代码 并希望找到框字符串中数字的索引 所以我用了findIndex但它返回Maybe Int值 而我只想要Int value 我怎样才能转换Maybe Int to Int值或者有什么方法可以提取Int from Maybe
  • 在 Haskell 中阅读 GraphML

    我正在尝试将包含单个有向图的 GraphML 文件读入 HaskellData Graph http hackage haskell org package containers 0 2 0 1 docs Data Graph html为了
  • Haskell 中的异构多态性(正确方法)

    让一个模块来抽象Area操作 错误的定义 class Area someShapeType where area someShapeType gt Float module utilities sumAreas Area someShape
  • Accelerate 和 Repa 是否有不同的用例?

    我一直在玩 Repa 和 Accelerate 它们都很有趣 但我不知道何时使用其中一个 何时使用另一个 他们是一起成长 是竞争对手 还是只是为了解决不同的问题 Repa 是一个用于高效数组构建和遍历的库 用 Haskell 编程并在 Ha
  • Haskell 中函数和函子有什么区别?只有定义吗?

    在 Haskell 中 当编写函数时 这意味着我们将某个东西 输入 映射到另一个东西 输出 我尝试 LYAH 来理解 Functor 的定义 看起来和普通 Functor 一样 函数被称为函子有什么限制吗 Functor 是否允许有 I O
  • 如何在 Yesod 中使用 CSS 框架?

    我想将 Blueprint CSS 框架与 Yesod 一起使用 有没有最佳实践 因为 Yesod 使用 CSS 模板 所以在我看来我不能直接使用 css 文件 我必须将它们重命名为 lucius files 吗 如何将 CSS 添加到 d
  • 整数转浮点数

    这段代码的工作原理 posToXY Float gt Float gt Integer posToXY a b do let y a b round y 但这不起作用 posToXY Integer gt Integer gt Intege
  • 访问函数中的环境

    In main我可以读取我的配置文件 并将其提供为runReader somefunc myEnv正好 但somefunc不需要访问myEnv读者提供 链中的下一对也没有提供 需要 myEnv 中某些内容的函数是一个微小的叶函数 如何在不将
  • 这个记忆的斐波那契函数是如何工作的?

    在我正在做的函数式编程课程的当前练习作业中 我们必须制作给定函数的记忆版本 为了解释记忆化 给出以下示例 fiblist fibm x x lt 0 fibm 0 0 fibm 1 1 fibm n fiblist n 1 fiblist
  • 将数据类型设置为 Kind * -> * 这不是函子

    布伦特 约尔吉类型分类百科全书 https www haskell org haskellwiki Typeclassopedia给出以下练习 举一个类型的例子 gt 不能将其制成 的实例Functor 不使用undefined 请告诉我什
  • 无点镜头创建不进行类型检查

    在函数中test 我遍历一个列表 从它的成员生成镜头 然后打印一些数据 当我使用有针对性的呼叫风格时 这会起作用 当我使其成为无点时 它无法进行类型检查 为什么会出现这种情况 我该如何解决这个问题 在我看来 GHC 并没有保留排名较高的信息
  • 如何在 Haskell 中向右或向左移动列表的 1 个元素?

    嗨 我一直在寻找答案 但找不到 假设我们有一个像这样的列表 1 10 4 5 3 我怎样才能将 5 向左移动 使这个列表变成 1 10 5 4 3 我尝试过了swapElementsAt通过找到该元素的索引 但它看起来非常不足 swapEl
  • Haskell,堆栈:找到可执行文件

    我正在寻找类似的东西 stack whereis hasktags where whereis行为或多或少类似于 UNIXwhereis命令 hasktags是这样运行的 stack exec hasktags stack exec whe
  • Haskell 中的分类结构

    Hask通常被认为是一个范畴 其对象是类型 态射是函数 然而 我看到 Conor McBride pigworker 警告不要使用Hask多次 1 https stackoverflow com a 45905082 474311 2 ht
  • 规范化且不可变的数据模型

    Haskell如何解决 规范化不可变数据结构 问题 例如 让我们考虑一个表示前女友 男友的数据结构 data Man Man name String exes Woman data Woman Woman name String exes
  • “Eta减少”并不总是在Haskell中举行?

    我发现我可以说 LANGUAGE RankNTypes f1 forall b b gt b gt forall c c gt c f1 f id f HLint 告诉我我可以在这里做 Eta 减少 但是 f2 forall b b gt
  • Haskell 中列表列表的笛卡尔积

    给定一个长度列表的列表x所有子列表的长度都相同y 输出y x长度列表x包含每个子列表中的一项 例子 x 3 y 2 1 2 3 4 5 6 Output 2 3 8不同的输出 1 3 5 1 4 5 1 3 6 1 4 6 2 3 5 2
  • 在 Yesod 生态系统中,对某些文本进行 urlencode 的最佳方式是什么?

    我想对一些文本进行 url 编码 例如 用 20 替换每个空格等 我找到了 HTTP Network HTTP Base urlEncode 并且可以使用它 但我想知道是否还有其他通常在 Yesod 生态系统中使用的东西 不幸的是 由于 U
  • Haskell / GHC - 是否有“警告不完整模式”的中缀标签/编译指示

    我正在寻找一个可以对特定的不完整模式发出警告的编译指示 它会使编译器失败并显示以下 假设的 代码 FAILIF incomplete patterns f Int gt Int f 0 0 我正在尝试使用 Arrows 编写一个 编译器 并
  • 有没有更好的方法将 UTC 时间转换为大纪元时间?

    我想将文件的修改时间设置为从 exif 数据获取的时间 为了从 exif 获取时间 我发现 Graphics Exif getTag Exif gt String gt IO Maybe String 要设置文件修改时间 我发现 Syste

随机推荐