我在 Haskell 中使用了一個庫,它有一個非常非常復雜的遞回資料結構,它代表了一個 AST。它包含許多不同的建構式,有些具有簡單的遞回定義,有些具有相互遞回的定義,而且都很討厭。
我希望能夠將這個巨大的遞回怪物序列化為 JSON 字串,然后能夠對其進行反序列化。它是一個資料類,所以我覺得我應該能夠擁有某種通用函式,將其轉換為 JSON 格式的巨大的人類可讀字串。我真的非常想避免為 80 多個建構式撰寫自定義序列化邏輯。
這甚至可能嗎?
為了澄清,我正在嘗試序列化這個資料結構,它是官方 GHC API 的一部分。我知道漂亮的列印給了我一個字串,但我真的很喜歡這個作為 JSON 結構。
編輯:該類對于 Generic 來說太復雜了,無法創建合適的 ToJSON 和 FromJSON,除非我遺漏了一些東西。
uj5u.com熱心網友回復:
唯一合理的方法是使用獨立的派生子句Generic為(大多數)所涉及的型別派生實體,并使用基于 default 的默認值生成盡可能多的FromJSON/ToJSON實體Generic。
我開始擺弄它,并沒有看到無法克服的技術障礙,但所需的樣板數量并非微不足道。您將需要大量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通過型別族使用 phase 引數來更改樹部分的型別,因此是一個多型實體:
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. --
From there, it's a matter for following the trail of compiler error messages re: missing instances and filling them all in. A few keyboard macros in your editor of choice should ease the pain.
You'll eventually get down to some leaf types that probably shouldn't be serialized generically. For example, FastString is a string stored in a common hash table for fast comparison, and you'll want/need to serialize and deserialize it manually (or deal with reconstructing the hash table on the deserialized end).
Anyway, I stopped after around 35 Generic instances and 50 FromJSON instances, and I figure I was only about a quarter done at that point. On the other hand, that took me less than an hour, so I think it's doable with a day or two of tedious work.
Here's what I had before I lost interest. About half of the FromJSON instances typecheck; the rest are still demanding instances. I was using GHC 8.10.7, though, so the module names and types probably won't match yours.
{-# 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
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/440928.html
