[Haskell-cafe] Using GHC.Generics to print data type structure

J. Stutterheim j.stutterheim at me.com
Sun Apr 13 13:22:39 UTC 2014

Hi all,

I'm trying to use GHC.Generics to print a data type's structure. I have a test type TestRecord:

	data TestRecord = TestRecord
		{ trId :: Int
		, someStr :: String }
		deriving Generic 

And a PrintDT class:

	class PrintDT a where
		printDT :: a -> String

		default printDT :: (Generic a, GPrintDT (Rep a)) => a -> String
		printDT = gprintDT . from

With a corresponding instance for TestRecord. The GPrintDT class and instances are defined as follows:

	class GPrintDT f where
		gprintDT :: f a -> String

	instance (GPrintDT a, GPrintDT b) => GPrintDT (a :*: b) where
		gprintDT (x :*: y) = " { " ++ gprintDT x ++ ", " ++ gprintDT y ++ " }"

	instance (Datatype d, GPrintDT f) => GPrintDT (D1 d f) where
		gprintDT d = "data " ++ datatypeName d ++ " = " ++ (gprintDT $ unM1 d)

	instance (Constructor c, GPrintDT f) => GPrintDT (C1 c f) where
		gprintDT con
			| conIsRecord con = conName con ++ (gprintDT $ unM1 con)
			| otherwise       = "No record"

	instance (Selector s, GPrintDT a) => GPrintDT (S1 s a) where
		gprintDT m = selName m

	instance (PrintDT a) => GPrintDT (K1 i a) where
		gprintDT _ = ""

	instance PrintDT Int where
		printDT n = show n

	instance PrintDT String where
		printDT xs = xs

In a first attempt, I apply printDT to a TestRecord value:

	test1 :: String
	test1 = printDT (TestRecord 1 "foo")

This prints the expected result:

	"data TestRecord = TestRecord { trId, someStr }"

Now ideally, I wouldn't have to specify some value of TestRecord to get this output, since so far, I'm only printing the structure of the TestRecord type, not the values. I would want the following to give me the same result string:

	test2 :: String
	test2 = printDT (undefined :: TestRecord) 

With the current implementation, test2 gives me the following output:

	"data TestRecord = TestRecord*** Exception: Prelude.undefined

Is there a way to implement GPrintDT such that test2 gives me the same output as test1?


- Jurriën

More information about the Haskell-Cafe mailing list