2016-07-22 67 views
1

我想序列化一個由我自己部分定義的數據結構,部分是使用來自外部庫(它是Data的一個實例)的數據結構。我想做序列化,而不必定義序列化過程應該如何工作,或換句話說,以一種相當自動的方式。如何序列化一個Data實例的數據結構?

我一直在嘗試幾個替代方案,我找到了谷歌搜索/問。他們都沒有成功。圖書館(genericserialize)似乎我正在尋找。不幸的是,即使對於簡單的情況,它也不起作用(如(True,False))。它可能已過時或/和不完整。二進制序列化要求外部數據結構派生二進制(它不)。隨着Cereal出現類似的問題。當然,它是Read/Show,但是外部數據結構不會派生Read,所以它也不能被使用。

也許我誤解了一些東西。我想,當我第一次面對這個問題時,它會更容易。在其他語言中,比如Erlang,這是以一種非常簡單的方式完成的。

你知道圖書館/技術或任何使這個過程儘可能簡單嗎?

回答

2

您可以使用Data.Binary

對於涉及的所有數據類型,派生Generic。這將需要-XDeriveGeneric編譯指示。如果您正在使用的外部庫的數據類型不這樣做,則可能必須有一個orphan instances的模塊並使用-XStandaloneDeriving

一旦完成,您可以使用Binary類已支持從Generic派生的事實。您需要啓用-XDeriveAnyclass,然後您可以爲涉及的所有數據類型添加Binary實例(您可能需要再次爲來自外部庫的類型創建獨立實例)。

編輯

OP added a gist。然後,爲了得到這個編譯,我們需要添加以下語言編譯指示:

{-# LANGUAGE DeriveDataTypeable, 
      DeriveAnyClass, 
      DeriveGeneric, 
      StandaloneDeriving #-} 

而下面的進口:

import Language.C.Syntax.AST 
import Language.C.Data.Position 
import Language.C.Data.Node 
import Language.C.Data.Name 
import Language.C.Data.Ident 
import Language.C.Syntax.Constants 

import Data.Data 
import GHC.Generics 
import Data.Binary 

從OP的要點:

type CTypeSpecAnn = CTypeSpecifier NodeAnn 
type CDeclAnn = CDeclaration NodeAnn 
type CDeclSpecAnn = CDeclarationSpecifier NodeAnn 
type CDeclrAnn = CDeclarator NodeAnn 
type CStatAnn = CStatement NodeAnn 
type CExtDeclAnn = CExternalDeclaration NodeAnn 
type CExprAnn = CExpression NodeAnn 
type CBlockItemAnn = CCompoundBlockItem NodeAnn 
type CTranslUnitAnn = CTranslationUnit NodeAnn 

data TransState = 
    TransState 
    { 
     free_node_id :: Int, 
     freeVar :: Int, 
     includes :: [String], 
     fun_defs :: [(String, (CTypeSpecAnn, [CDeclAnn], ([CDeclSpecAnn], CDeclrAnn, [CDeclAnn], NodeAnn)), CStatAnn)], 
     no_fun_defs :: [CExtDeclAnn], 
     last_changed :: String, 
     previous_changes :: ([(String, ((String,CStatAnn,CStatAnn), TransState, [(String, CStatAnn)]))], [(String, ((String,CExprAnn,CExprAnn), TransState, [(String, CStatAnn)]))]), 
     applied_rules :: [String], 
     applicable_rules :: Set String, 
     trans_with_anns :: Bool 
    } 
    deriving (Show, Data, Typeable) 

type NodeAnn = Annotation NodeInfo NodeProperties 
data Annotation nI nP = Ann nI nP 
    deriving (Show, Data, Typeable, Eq) 

data NodeProperties = 
    NodeProperties 
    { 
     _hasSideEffects :: PropertyInfo Bool, 
     _readIn :: PropertyInfo [String], 
     _writeIn :: PropertyInfo [String], 
     _localSymbols :: PropertyInfo [String], 
     _rangeInfo :: PropertyInfo [String], 
     _isCanonical :: PropertyInfo Bool, 
     _isPerfectNest :: PropertyInfo Bool, 
     _hasLoops :: PropertyInfo Bool, 
     _hasFunctionCalls :: PropertyInfo Bool, 
     _hasControlFlowModifiers :: PropertyInfo Bool, 
     _scalarDependences :: PropertyInfo [String], 
     _polcaPragmas :: PropertyInfo [[String]], 
     _allPragmas :: PropertyInfo [String] 
    } 
    deriving (Show, Data, Typeable, Eq) 

data PropertyInfo a = 
    PropertyInfo 
    { 
     _pragmaType :: PragmaType, 
     _definedBy :: DefinerType, 
     _value :: Maybe a 
    } 
    deriving (Show, Data, Typeable, Eq) 

makeLenses ''NodeProperties 
makeLenses ''PropertyInfo 

由於OP從來沒有定義PragmaTypeDefinerType,我假設他們是()

type PragmaType =() 
type DefinerType =() 

然後我們有一噸的deriving instance(我們有遞歸找到所有類型的依賴,並添加GenericBinary他們)。

deriving instance Generic (CDeclaration a) 
deriving instance Binary a => Binary (CDeclaration a) 
deriving instance Generic (CTypeSpecifier a) 
deriving instance Binary a => Binary (CTypeSpecifier a) 
deriving instance Generic (CDeclarationSpecifier a) 
deriving instance Binary a => Binary (CDeclarationSpecifier a) 
deriving instance Generic (CDeclarator a) 
deriving instance Binary a => Binary (CDeclarator a) 
deriving instance Generic (CStatement a) 
deriving instance Binary a => Binary (CStatement a) 
deriving instance Generic (CExternalDeclaration a) 
deriving instance Binary a => Binary (CExternalDeclaration a) 
deriving instance Generic (CExpression a) 
deriving instance Binary a => Binary (CExpression a) 
deriving instance Generic (CCompoundBlockItem a) 
deriving instance Binary a => Binary (CCompoundBlockItem a) 
deriving instance Generic (CTranslationUnit a) 
deriving instance Binary a => Binary (CTranslationUnit a) 
deriving instance Generic (CInitializer a) 
deriving instance Binary a => Binary (CInitializer a) 
deriving instance Generic (CStructureUnion a) 
deriving instance Binary a => Binary (CStructureUnion a) 
deriving instance Generic (CTypeQualifier a) 
deriving instance Binary a => Binary (CTypeQualifier a) 
deriving instance Generic (CStringLiteral a) 
deriving instance Binary a => Binary (CStringLiteral a) 
deriving instance Generic (CAttribute a) 
deriving instance Binary a => Binary (CAttribute a) 
deriving instance Generic (CPartDesignator a) 
deriving instance Binary a => Binary (CPartDesignator a) 
deriving instance Generic (CFunctionDef a) 
deriving instance Binary a => Binary (CFunctionDef a) 
deriving instance Generic (CAssemblyStatement a) 
deriving instance Binary a => Binary (CAssemblyStatement a) 
deriving instance Generic (CAssemblyOperand a) 
deriving instance Binary a => Binary (CAssemblyOperand a) 
deriving instance Generic (CConstant a) 
deriving instance Binary a => Binary (CConstant a) 
deriving instance Generic (CEnumeration a) 
deriving instance Binary a => Binary (CEnumeration a) 
deriving instance Generic (CStorageSpecifier a) 
deriving instance Binary a => Binary (CStorageSpecifier a) 
deriving instance Generic (CDerivedDeclarator a) 
deriving instance Binary a => Binary (CDerivedDeclarator a) 
deriving instance Generic (CBuiltinThing a) 
deriving instance Binary a => Binary (CBuiltinThing a) 
deriving instance Generic (CArraySize a) 
deriving instance Binary a => Binary (CArraySize a) 
deriving instance Generic (Flags a) 
deriving instance Binary a => Binary (Flags a) 
deriving instance Generic NodeInfo 
deriving instance Binary NodeInfo 
deriving instance Generic Name 
deriving instance Binary Name 
deriving instance Generic Ident 
deriving instance Binary Ident 
deriving instance Generic CString 
deriving instance Binary CString 
deriving instance Generic CStructTag 
deriving instance Binary CStructTag 
deriving instance Generic CFloat 
deriving instance Binary CFloat 
deriving instance Generic CChar 
deriving instance Binary CChar 
deriving instance Generic CUnaryOp 
deriving instance Binary CUnaryOp 
deriving instance Generic CBinaryOp 
deriving instance Binary CBinaryOp 
deriving instance Generic CInteger 
deriving instance Binary CInteger 
deriving instance Generic CAssignOp 
deriving instance Binary CAssignOp 
deriving instance Generic CIntFlag 
deriving instance Binary CIntFlag 
deriving instance Generic CIntRepr 
deriving instance Binary CIntRepr 

deriving instance Binary TransState 
deriving instance Generic TransState 
deriving instance Generic (Annotation a b) 
deriving instance (Binary a, Binary b) => Binary (Annotation a b) 
deriving instance Generic NodeProperties 
deriving instance Binary NodeProperties 
deriving instance Generic (PropertyInfo a) 
deriving instance Binary a => Binary (PropertyInfo a) 

作爲一個側面說明,這些實例下半年可在類型的數據聲明自行申報(因爲這些在當前文件中聲明)。一個棘手的問題是,我們仍然沒有Binary實例Position。我們不能自動派生它,因爲它的數據構造函數沒有被導出。但是,沒有任何東西阻止我們編寫手冊Binary實例。

instance Binary Position where 
    put p | isNoPos p = putWord8 0 
      | isBuiltinPos p = putWord8 1 
      | isInternalPos p = putWord8 2 
      | isSourcePos p = putWord8 3 >> put (posOffset p) >> put (posFile p) >> put (posRow p) >> put (posColumn p) 

    get = do 
     marker <- getWord8 
     case marker of 
      0 -> return nopos 
      1 -> return builtinPos 
      2 -> return internalPos 
      3 -> position <$> get <*> get <*> get <*> get 
+0

感謝您的快速答覆。我試圖獲得通用的,但我發現了以下錯誤: 預期的那種 '(* - > *) - > GHC.Prim.Constraint', 但 '通用' 有種「(* - > * ) - > *' 在'Trans'的數據聲明中 –

+0

'Trans'的數據定義是什麼樣子的? – Alec

+0

@SalvadorTamarit實際上,即使鏈接到圖書館文檔也會有幫助... – Alec