我在Haskell中使用一个库,该库具有非常非常复杂的递归数据结构,表示AST。它包含几十个不同的构造函数,有些具有简单的递归定义,有些具有相互递归的定义,而且都是令人讨厌的。
我希望能够将这个巨大的递归怪物序列化为JSON字符串,然后能够对其进行反序列化。这是一个数据类,所以我觉得我应该能够拥有某种通用函数,将其转换为JSON格式的巨大人类可读字符串。我真的,真的想避免为它的80+构造函数编写自定义序列化逻辑。
这可能吗?
为了澄清,我试图序列化这个数据结构,它是官方GHC API的一部分。我知道漂亮的打印会给我一个字符串,但我真的很喜欢这个JSON结构。
EDIT:这个类太复杂了,Generic无法创建合适的ToJSON和FromJSON,除非我遗漏了什么。
唯一合理的方法是使用独立的派生子句来派生(大多数(相关类型的Generic
实例,并使用默认的基于Generic
的默认值生成尽可能多的FromJSON
/ToJSON
实例。
我开始摆弄它,我没有看到任何不可逾越的技术障碍,但所需的样板数量并不是微不足道的。您将需要一船Generic
实例。您可能还需要使用ghc-lib
源的修改副本,因为某些类型(例如TyCon
(不会与其构造函数一起导出,从而阻止了实例的派生。
总的来说,Generic
实例并没有那么糟糕,因为大多数实例都可以在阶段进行多态性推导
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
import BasicTypes
import CoAxiom
-- etc. --
import GHC.Generics
deriving instance Generic (AnnDecl p)
deriving instance Generic (AnnProvenance p)
deriving instance Generic (Branches br)
deriving instance Generic (CoAxiom br)
deriving instance Generic (ForeignDecl p)
deriving instance Generic (GenLocated l e)
deriving instance Generic (HsBracket p)
deriving instance Generic (HsExpr p)
-- etc. --
FromJSON
、ToJSON
实例稍微困难一些。阶段参数通过类型族用于更改树部分中的类型,因此多态实例:
import Data.Aeson
instance FromJSON (HSExpr p)
将开始要求大量类型的族实例,如instance FromJSON (XWrap p)
和其他几十个实例。你不能提供这些多态性:
instance FromJSON (XWrap p) -- Illegal type synonym family application
因为他们是典型的家庭,而GHC不支持这一点。我认为最好的方法是为每个需要的阶段定义实例,并且由于存在一些阶段间依赖关系,因此您需要为多个阶段定义实例——即使您只尝试为一个阶段序列化。因此:
instance FromJSON (HSExpr GhcTc)
instance FromJSON (HSExpr GhcRn)
-- etc. --
从那以后,就需要跟踪编译器错误消息:丢失实例并将其全部填充。在编辑器中选择一些键盘宏应该可以减轻这种痛苦。
您最终将了解到一些可能不应该进行泛型序列化的叶类型。例如,FastString
是一个存储在通用哈希表中的字符串,用于快速比较,您需要手动对其进行序列化和反序列化(或在反序列化端重建哈希表(。
无论如何,我在大约35个Generic
实例和50个FromJSON
实例之后停止了,我想我当时只完成了大约四分之一。另一方面,这花了我不到一个小时的时间,所以我认为这对一两天乏味的工作来说是可行的。
这是我失去兴趣之前的东西。大约一半的FromJSON
实例进行了类型检查;其余的例子仍然要求很高。不过,我使用的是GHC 8.10.7,所以模块名称和类型可能与您的不匹配。
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TemplateHaskell #-}
module MyModule where
import BasicTypes
import CoAxiom
import FastString
import GHC.Hs
import GHC.Hs.Extension
import Name
import SrcLoc
import TyCoRep
import TyCon
import Unique
import UniqSet
import Var
import qualified Data.Array as Array
import GHC.Generics
import Data.Aeson
deriving instance Generic (AnnDecl p)
deriving instance Generic (AnnProvenance p)
deriving instance Generic (Branches br)
deriving instance Generic (CoAxiom br)
deriving instance Generic (ForeignDecl p)
deriving instance Generic (GenLocated l e)
deriving instance Generic (HsBracket p)
deriving instance Generic (HsExpr p)
deriving instance Generic (HsGroup p)
deriving instance Generic (HsImplicitBndrs p (LHsType p))
deriving instance Generic (HsRecField' id arg)
deriving instance Generic (HsSplice p)
deriving instance Generic (HsType p)
deriving instance Generic (HsWildCardBndrs p (LHsType p))
deriving instance Generic (Match p (LHsExpr p))
deriving instance Generic (MatchGroup p (LHsExpr p))
deriving instance Generic (RuleDecls p)
deriving instance Generic (StmtLR p p (LHsExpr p))
deriving instance Generic (VarBndr var argf)
deriving instance Generic (WarnDecl p)
deriving instance Generic (WarnDecls p)
deriving instance Generic AnonArgFlag
deriving instance Generic ArgFlag
deriving instance Generic CoAxBranch
deriving instance Generic Coercion
deriving instance Generic ForeignImport
deriving instance Generic NoExtCon
deriving instance Generic NoExtField
deriving instance Generic Role
deriving instance Generic SourceText
deriving instance Generic SrcSpan
deriving instance Generic StringLiteral
deriving instance Generic TyLit
deriving instance Generic Type
deriving instance Generic WarningTxt
instance (FromJSON l, FromJSON e) => FromJSON (GenLocated l e)
instance FromJSON (AnnDecl GhcTc)
instance FromJSON (AnnProvenance Var)
instance FromJSON (Branches br)
instance FromJSON (CoAxiom Branched)
instance FromJSON (ConDeclField GhcRn)
instance FromJSON (ConDeclField GhcTc)
instance FromJSON (ForeignDecl GhcTc)
instance FromJSON (GRHS GhcTc (LHsExpr GhcTc))
instance FromJSON (HsBracket GhcRn)
instance FromJSON (HsBracket GhcTc)
instance FromJSON (HsExpr GhcRn)
instance FromJSON (HsExpr GhcTc)
instance FromJSON (HsGroup GhcRn)
instance FromJSON (HsGroup GhcTc)
instance FromJSON (HsImplicitBndrs GhcTc (LHsExpr GhcTc))
instance FromJSON (HsImplicitBndrs GhcTc (LHsType GhcTc))
instance FromJSON (HsLocalBindsLR GhcTc GhcTc)
instance FromJSON (HsRecField' (AmbiguousFieldOcc GhcTc) (LHsExpr GhcTc))
instance FromJSON (HsRecFields GhcTc (LHsExpr GhcTc))
instance FromJSON (HsSplice GhcTc)
instance FromJSON (HsTyVarBndr GhcRn)
instance FromJSON (HsTyVarBndr GhcTc)
instance FromJSON (HsType GhcRn)
instance FromJSON (HsType GhcTc)
instance FromJSON (HsValBindsLR GhcTc GhcTc)
instance FromJSON (HsWildCardBndrs GhcRn (LHsSigType GhcRn))
instance FromJSON (HsWildCardBndrs GhcRn (LHsType GhcRn))
instance FromJSON (Match GhcTc (LHsExpr GhcTc))
instance FromJSON (MatchGroup GhcTc (LHsExpr GhcTc))
instance FromJSON (RuleDecls GhcRn)
instance FromJSON (RuleDecls GhcTc)
instance FromJSON (StmtLR GhcRn GhcRn (LHsExpr GhcRn))
instance FromJSON (StmtLR GhcTc GhcTc (LHsExpr GhcTc))
instance FromJSON (VarBndr TyCoVar ArgFlag)
instance FromJSON (WarnDecl GhcTc)
instance FromJSON (WarnDecls GhcTc)
instance FromJSON AnonArgFlag
instance FromJSON ArgFlag
instance FromJSON CoAxBranch
instance FromJSON Coercion
instance FromJSON ForeignImport
instance FromJSON NoExtField
instance FromJSON Role
instance FromJSON SourceText
instance FromJSON SrcSpan
instance FromJSON StringLiteral
instance FromJSON TyLit
instance FromJSON Type
instance FromJSON WarningTxt
-- Non-generic instances, a mixture of:
-- 1. Those that shouldn't be derived generically (e.g., FastString)
-- 2. Those that will need access to the constructors (e.g., TyCon)
instance FromJSON RealSrcSpan where parseJSON = undefined
instance FromJSON FastString where parseJSON = undefined
instance FromJSON a => FromJSON (UniqSet a) where parseJSON = undefined
instance FromJSON Var where parseJSON = undefined
instance FromJSON NoExtCon where parseJSON = undefined
instance (FromJSON i, FromJSON e) => FromJSON (Array.Array i e) where parseJSON = undefined
instance FromJSON TyCon where parseJSON = undefined
instance FromJSON Unique where parseJSON = undefined
instance FromJSON Name where parseJSON = undefined
;报废你的样板"(syb(图书馆有";gshow";以及";gread";函数,可以读取和加载Haskell中的大多数Data类,但具有私有字段或构造函数的Data类除外。