packages feed

typehash (empty) → 1.0.0.0

raw patch · 3 files changed

+71/−0 lines, 3 filesdep +basedep +mtlsetup-changed

Dependencies added: base, mtl

Files

+ Setup.hs view
@@ -0,0 +1,3 @@+module Main where+import Distribution.Simple+main = defaultMain
+ src/Data/TypeHash.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable #-}+-- | Produce a /hash/ for a type that is unique for that type.+-- The hash takes both actual type names and type structure into account.+--+-- The purpose of the hash of a type is to be able to store the type+-- of a persisted value together with the value.+-- By comparing the type hash of a persisted value and the expected value+-- we can know if the persistened value is of the correct type.+--+-- The current implementation is not really a hash, but a string representation+-- of the type structure.+module Data.TypeHash where+import Data.Char(isAlpha)+import Control.Monad.State+import Data.Generics++-- | The type of a hashed type.+newtype TypeHash = TypeHash String+    deriving (Eq, Ord, Typeable, Data, Show, Read)++-- | Turn the type of the value into a type hash.+typeHash :: (Data a) => a -> TypeHash+typeHash = TypeHash . show . gType []++data Type+    = Name { typeName :: String }            -- Abstract type, or recursive reference+    | Data { typeName :: String, constrs :: [(String, [Field])] }+    deriving (Eq, Ord, Show)++type Field = (String, Type)  -- a "_" string for missing field names++gType :: (Data a) => [String] -> a -> Type+gType tns x =+    let tn = show $ fullTypeOf x+    in  case dataTypeRep $ dataTypeOf x of+        AlgRep cs | tn `notElem` tns ->+            Data { typeName = tn, constrs = map (gConstr (tn:tns) x) cs }+        _ -> Name { typeName = tn }++gConstr :: (Data a) => [String] -> a -> Constr -> (String, [Field])+gConstr tns x c = (showConstr c,+                   zip fs (reverse $ execState (fromConstrM f c `asTypeOf` return x) []))+  where fs = constrFields c ++ repeat "_"+        f :: forall d . (Data d) => State [Type] d+        f = do modify (gType tns (undefined :: d) :); return undefined++-- Replace unqualified type name by qualified type name.+-- XXX Only does it on the top level, because I don't know how to get deeper.+fullTypeOf :: (Data a) => a -> TypeRep+fullTypeOf a | not $ isAlpha $ head $ tyConString $ typeRepTyCon $ ta = ta+	     | otherwise = mkTyConApp (mkTyCon $ dataTypeName $ dataTypeOf a)+                                      (typeRepArgs ta)+  where ta = typeOf a
+ typehash.cabal view
@@ -0,0 +1,15 @@+Name:		typehash+Version:	1.0.0.0+License:	BSD3+Author:		Lennart Augustsson+Maintainer:	Lennart Augustsson+Category:	Reflection+Synopsis:	Create a unique hash value for a type.+Stability:      experimental+Build-type:	Simple+Description:	Produce a hash for a type that is unique for that type.+		The hash takes both actual type names and type structure into account.+		This is useful for checking the type of persisted values.+Hs-Source-Dirs: src+Build-Depends:	base, mtl+Exposed-modules:	Data.TypeHash