I have a Haskell project, which uses a few newtypes.
I would like to export a table of these, so I can include it in my documentation (not-haddock), as a markdown table for instance. I'm not familiar with this, but from reading around, my plan was to use Generics/Data.Data, to create some functions that broadly look as follows:
data MyRowRepresentation = MyRowRepresentation
String -- Name of the newtype
String -- Name of the type its wrapping
toDocRow :: (Generic a, HasDatatypeInfo a) -> (Proxy a) -> MyRowRepresentation
toDocRow = <the part I'm struggling with>
newtype MyType0 = MyType0 Int16
newtype MyType1 = MyType0 Int8
newtype MyType2 = MyType0 Int32
newtype MyType3 = MyType0 Word8
main = do
let table = [
toDocRow (Proxy::MyType0),
toDocRow (Proxy::MyType1),
toDocRow (Proxy::MyType2),
toDocRow (Proxy::MyType3),
]
-- Do something to write `table` to disk.
However, I am struggling to understand how Generics/Data.Data interacts with Constructors. Its my first time using area of Haskell, so I tried the following code, just to see how it worked:
{-# LANGUAGE DeriveGeneric #-}
module TmpTmpExport where
import RIO
import RIO.List.Partial (head)
import Text.Show.Pretty
import Data.String.Conversions (cs)
import Data.Data
newtype MyNewType = MyNewType Integer
deriving (Show)
deriving (Data, Typeable)
main :: IO ()
main = do
traceM $ cs $ "INSTANCE: " ++ (show $ dataTypeConstrs $ dataTypeOf $ (MyNewType 0))
traceM $ cs $ "INSTANCE constrType: " ++ (show $ constrType $ head $ dataTypeConstrs $ dataTypeOf $ (MyNewType 0))
traceM $ cs $ "INSTANCE constrType: " ++ (show $ dataTypeConstrs $ constrType $ head $ dataTypeConstrs $ dataTypeOf $ (MyNewType 0))
traceM $ cs $ "INSTANCE constrType: " ++ (show $ (fmap showConstr) $ dataTypeConstrs $ constrType $ head $ dataTypeConstrs $ dataTypeOf $ (MyNewType 0))
traceM $ cs $ "INSTANCE constrType: " ++ (show $ dataTypeConstrs $ constrType $ head $ dataTypeConstrs $ constrType $ head $ dataTypeConstrs $ constrType $ head $ dataTypeConstrs $ dataTypeOf $ (MyNewType 0))
return ()
Which gives the following output:
INSTANCE: [MyNewType]
INSTANCE constrType: DataType {tycon = "MyNewType", datarep = AlgRep [MyNewType]}
INSTANCE constrType: [MyNewType]
INSTANCE constrType: ["MyNewType"]
INSTANCE constrType: [MyNewType]
I don't think I'm a million miles away, but from reading the documentation for Data.Data, and trying various functions out, I couldn't work out how to "get inside" the newtype using dataTypeConstrs and constrType, so that I can create table with rows like:
table = [
(MyRowRepresentation "Type0" "Int16"),
(MyRowRepresentation "Type1" "Int8")
(MyRowRepresentation "Type2" "Int32")
(MyRowRepresentation "Type3" "Word8")
]
Have I conceptually missed something about the difference between newtype and data, is this possible to do with Data.Data, or should I be looking at a different tool/library?