Accessing record name and function in generics - haskell

I am trying to figure out how to do generic deriving modeled after deriveJSON. I defined a simple type using record style data constructor as below:
data T = C1 { aInt::Int, aString::String} deriving (Show,Generic)
What I will like to do is to define a generic derivable function that takes the data constructors above, and outputs a builder using the record names and the functions - just a toy code - we want to make ABuilder generic so we can use it for any data type with record syntax (like deriveJSON in Aeson):
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
data T = C1 { aInt::Int, aString::String} deriving (Show,Generic)
-- Some kind of builder output - String here is a stand-in for the
-- builder
class ABuilder a where
f :: a -> String
-- Need to get the record field name, and record field function
-- for each argument, and build string - for anything that is not
-- a string, we need to add show function - we assume "Show" instance
-- exists
instance ABuilder T where
f x = ("aInt:" ++ (show . aInt $ x)) ++ "," ++ ("aString:" ++ (aString $ x))
What I can't figure out is how to get the record name, and the function. Here is my attempt in ghci 7.10.3. I could get the data type name, but can't figure out how to get record names and functions out of it.
$ ghci Test.hs
GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Main ( Test.hs, interpreted )
Ok, modules loaded: Main.
*Main> datatypeName . from $ (C1 {aInt=1,aString="a"})
"T"
*Main> :t from (C1 {aInt=1,aString="a"})
from (C1 {aInt=1,aString="a"})
:: D1
Main.D1T
(C1
Main.C1_0T
(S1 Main.S1_0_0T (Rec0 Int) :*: S1 Main.S1_0_1T (Rec0 String)))
x
*Main>
I will appreciate pointers on how to get the record name and the function in Generics. If TemplateHaskell is better approach for defining Generic instance of ABuilder, I will appreciate hearing why. I am hoping to stick to Generics for solving this at compile-time if the solution is simple. I have noticed that Aeson uses TemplateHaskell for deriveJSON part. That is why my question about TemplateHaskell above to see if there is something I am missing here (I am using ghc 7.10.3 and don't need backward compatibility with older versions).

Here's something I just whipped up that should get this if you hand it the innards of a specific constructor:
{-# LANGUAGE DeriveGeneric, TypeOperators, FlexibleContexts, FlexibleInstances #-}
import GHC.Generics
data T = C1 { aInt::Int, aString::String} deriving (Show,Generic)
class AllSelNames x where
allSelNames :: x -> [String]
instance (AllSelNames (a p), AllSelNames (b p)) => AllSelNames ((a :*: b) p) where
allSelNames (x :*: y) = allSelNames x ++ allSelNames y
instance Selector s => AllSelNames (M1 S s f a) where
allSelNames x = [selName x]
From the repl we see
*Main> let x = unM1 . unM1 $ from (C1 {aInt=1,aString="a"})
*Main> allSelNames x
["aInt","aString"]

Related

Deriving Show Instance for ADT not working with Higher Kinded Type Families

I was just working through Chris Done's ADT with default example gist available here and ran into a problem: my ADT, with fields defined by higher kinded type families, is not working with a deriving show instance. GHC is telling me I need to derive a Show instance for a Type Family, but I'm not sure how to do. Here's what I have, so far, any comments would be helpful.
In the following example (using ghc 8.8.1), the objective is to define an instance of Show for ShowMe, using derive if possible.
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE ConstraintKinds #-}
data Tag = A | B deriving (Show)
type family TF (p :: Tag) a where
TF 'A a = ()
TF 'B a = a
data ShowMe p = ShowMe
{ a :: !(TF p String)
, b :: String
}
main = connect showMeDefaults { a = "some string" }
where
connect :: ShowMe B -> IO ()
connect _ = pure ()
showMeDefaults :: ShowMe A
showMeDefaults = ShowMe { a = (), b = "asdf" }
-- This works to define Show
{-
instance Show (ShowMe p) where
show _ = "hello"
-}
-- This instance is the line that causes an error
deriving instance Show (ShowMe p)
Subsequently, I'm getting an error that I'm not familiar with from GHC:
show_tf.hs:35:1: error:
• No instance for (Show (TF p String))
arising from a use of ‘showsPrec’
• In the first argument of ‘(.)’, namely ‘(showsPrec 0 b1)’
In the second argument of ‘(.)’, namely
‘((.)
(showsPrec 0 b1)
((.)
GHC.Show.showCommaSpace
((.)
(showString "b = ") ((.) (showsPrec 0 b2) (showString "}")))))’
In the second argument of ‘(.)’, namely
‘((.)
(showString "a = ")
((.)
(showsPrec 0 b1)
((.)
GHC.Show.showCommaSpace
((.)
(showString "b = ") ((.) (showsPrec 0 b2) (showString "}"))))))’
When typechecking the code for ‘showsPrec’
in a derived instance for ‘Show (ShowMe p)’:
To see the code I am typechecking, use -ddump-deriv
|
35 | deriving instance Show (ShowMe p)
If we recompile, using the ghc -ddump-deriv, the following is returned:
[1 of 1] Compiling Main ( show_tf.hs, show_tf.o )
==================== Derived instances ====================
Derived class instances:
instance GHC.Show.Show Main.Tag where
GHC.Show.showsPrec _ Main.A = GHC.Show.showString "A"
GHC.Show.showsPrec _ Main.B = GHC.Show.showString "B"
Derived type family instances:
==================== Filling in method body ====================
GHC.Show.Show [Main.Tag]
GHC.Show.show = GHC.Show.$dmshow #(Main.Tag)
==================== Filling in method body ====================
GHC.Show.Show [Main.Tag]
GHC.Show.showList = GHC.Show.$dmshowList #(Main.Tag)
Linking show_tf ...
Conceptually, I think what I should be able to derive a Show instance for TF, but when I do that, I get the following:
show_tf.hs:36:31: error:
• Illegal type synonym family application ‘TF 'A a’ in instance:
Show (TF 'A a)
• In the stand-alone deriving instance for
‘(Show a) => Show (TF 'A a)’
|
36 | deriving instance (Show a) => Show (TF 'A a)
This error also appears if I just try to define the Show instance myself for TF 'A a. I've searched "Illegal type synonym", and haven't come up up with a way around this.
You need to add
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
and then suggest the wanted context to GHC:
deriving instance Show (TF p String) => Show (ShowMe p)
GHC won't add that context automatically since it can be surprising to the programmer.

How can I implement fromJSON on a GADT with custom type class constraints?

I have the following GADT:
{-# LANGUAGE GADTs #-}
data LogProtocol a where
Message :: String -> LogProtocol String
StartRun :: forall rc. (Show rc, Eq rc, Titled rc, ToJSON rc, FromJSON rc)
=> rc -> LogProtocol rc
... and many more...
toJSON is straight forward and not shown.
fromJSON implementation is based on:
This SO Question and
This Blog Post - pattern 2
and is as follows:
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}
-- tag type is used in to/ from JSON to reduce the use of magic strings
data LPTag = MessageT |
StartRunT |
... and many more...
deriving (Show, Eq, Enum)
tagList :: Enum a => [a]
tagList = enumFrom $ toEnum 0
$(deriveJSON defaultOptions ''LPTag)
-- a wrapper to hide the a type param in the GADT
data Some (t :: k -> *) where
Some :: t x -> Some t
instance FromJSON (Some LogProtocol) where
parseJSON :: Value -> Parser (Some LogProtocol)
parseJSON v#(Object o) =
let
tag :: Maybe LPTag
tag = do
t <- (HML.lookup "type" o)
parseMaybe parseJSON t
failMessage :: [Char]
failMessage = toS $ "Could not parse LogProtocol no type field or type field value is not a member of specified in: "
<> (show(tagList :: [LPTag]))
<> show v
in
maybe
(fail failMessage )
(
\case
MessageT -> Some <$> (Message <$> o .: "txt")
StartRunT -> Some <$> (StartRun <$> o .: "runConfig")
)
tag
parseJSON wrng = typeMismatch "LogProtocol" wrng
The case for '''Message''' is fine. The problem I am having are errors such as:
* No instance for (Titled x2) arising from a use of `StartRun'
* In the first argument of `(<$>)', namely `StartRun'
In the second argument of `(<$>)', namely
`(StartRun <$> o .: "runConfig")'
In the expression: Some <$> (StartRun <$> o .: "runConfig")
Anywhere I have my own type class constraints (such as Titled)
in the data constructor the compiler says "No".
Is there a way to resolve this?
Existential types are an antipattern, especially if you need to do deserialization. StartRun should contain a concrete type instead. Deserialization requires a concrete type anyway, hence you might as well specialize StartRun to it.

Printing Dynamic Data

I have a system in haskell that uses Data.Dynamic and Type.Reflection to perform inference and calculations. I would like to be able to print the results.
Printing is easy when the type is supplied e.g
foo :: Dynamic -> String
foo dyn = case tyConName . someTypeRepTyCon . dynTypeRep $ dyn of
"Int" -> show $ fromDyn dyn (0 :: Int)
"Bool" -> show $ fromDyn dyn True
_ -> "no chance"
But if I want to be able to print tuples, I would have to add a new line for each e.g (Int, Bool), (Bool, Int), (Char, Int, Banana) ....
With the addition of more primitives and larger tuples this quickly becomes impractical.
Is there an algorithmic way to generate strings for this dynamic data, specifically for tuples and lists.
I like the main idea of the other answer, but it seems to get where it's going in a fairly roundabout way. Here's how I would style the same idea:
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GADTs #-}
import Type.Reflection
import Data.Dynamic
showDyn :: Dynamic -> String
showDyn (Dynamic (App (App (eqTypeRep (typeRep #(,)) -> Just HRefl) ta) tb) (va, vb))
= concat [ "DynamicPair("
, showDyn (Dynamic ta va)
, ","
, showDyn (Dynamic tb vb)
, ")"
]
showDyn (Dynamic (eqTypeRep (typeRep #Integer) -> Just HRefl) n) = show n
showDyn (Dynamic tr _) = show tr
That first pattern match is quite a mouthful, but after playing with a few different ways of formatting it I'm convinced that there just is no way to make that look good. You can try it in ghci:
> showDyn (toDyn ((3,4), (True, "hi")))
"DynamicPair(DynamicPair(3,4),DynamicPair(Bool,[Char]))"
I could only manage to obtain this horrible solution.
{-# LANGUAGE GADTs, ScopedTypeVariables, TypeApplications #-}
{-# OPTIONS -Wall #-}
import Type.Reflection
import Data.Dynamic
Here we define the TyCon for (,) and Int. (I'm pretty sure there must be an easier way.)
pairTyCon :: TyCon
pairTyCon = someTypeRepTyCon (someTypeRep [('a','b')])
intTyCon :: TyCon
intTyCon = someTypeRepTyCon (someTypeRep [42 :: Int])
Then we dissect the Dynamic type. First we check if it is an Int.
showDynamic :: Dynamic -> String
showDynamic x = case x of
Dynamic tr#(Con k) v | k == intTyCon ->
case eqTypeRep tr (typeRep # Int) of
Just HRefl -> show (v :: Int)
_ -> error "It really should be an int"
-- to be continued
The above is ugly, since we first pattern match against the TyCon using == instead of pattern matching, which prevents the type refinement of v into an Int. So, we still have to resort to eqTypeRep to perform a second check which we already know has to succeed.
I think it could be made pretty by checking eqTypeRep in advance, for instance. Or fromDyn. It does not matter.
What matters is that the pair case below is even more messy, and can not be made pretty in the same way, as far as I can see.
-- continuing from above
Dynamic tr#(App (App t0#(Con k :: TypeRep p)
(t1 :: TypeRep a1))
(t2 :: TypeRep a2)) v | k == pairTyCon ->
withTypeable t0 $
withTypeable t1 $
withTypeable t2 $
case ( eqTypeRep tr (typeRep #(p a1 a2))
, eqTypeRep (typeRep #p) (typeRep #(,))) of
(Just HRefl, Just HRefl) ->
"DynamicPair("
++ showDynamic (Dynamic t1 (fst v))
++ ", "
++ showDynamic (Dynamic t2 (snd v))
++ ")"
_ -> error "It really should be a pair!"
_ -> "Dynamic: not an int, not a pair"
Above we match the TypeRep so that it represents something of type p a1 a2. We require that the representation of p to be pairTyCon.
As before this does not trigger type refinement, since it is done with == instead of pattern matching. We need to perform another explicit match to force p ~ (,) and another for the final refinement v :: (a1,a2). Sigh.
Finally, we can take fst v and snd v, turn them into Dynamic once again, and pair them. Effectively, we turned the original x :: Dynamic into something like (fst x, snd x) where both components are Dynamic. Now we can recurse.
I would really like to avoid the errors, but I can not see how to do that at the moment.
The redeeming part is that the approach is very general, and can be easily adapted to other type constructors.

Creating a list of valid constructors

Consider the following:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GADTs #-}
data T = T1 | T2
data D (t :: T) where
D1 :: D T1
D2 :: D T2
D3 :: D d
D4 :: D T1
x1 :: [D T1]
x1 = [D1, D3, D4]
x2 :: [D T2]
x2 = [D2, D3]
Basically x1 is the list of all valid constructors for D T1, and x2 is the list of all valid constructors for D T2.
However, I want both this lists to reflect any additional constructors added to D, I don't want to hard code these lists like they are currently.
Is there a way to define x1 and x2 such that they are automatically generated from D?
Disclaimer - my TemplateHaskell-fu is almost non-existent - but I've investigated a bit which should give you a starting point to work with:
For those who don't know Template Haskell is a kind of meta-programming (language) that allows to write programs that run at compile time - it is type checked so it is safe (for some definition of safe, I think you can write programs that take infinite time to compile).
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
data T = T1 | T2
data D (t :: T) where
D1 :: D T1
D2 :: D T2
D3 :: D d
D4 :: D T1
You can start by loading the file into GHCi (don't forget to :set -XTemplateHaskell there)
> typeInfo = reify ''D
> $(stringE . show =<< typeInfo)
typeInfo is a Q Info that allows you to extract information from a type (escaped by '') - the $(..) works like print.
This gives you the template haskell Expression that constructs your (G)ADT:
TyConI (
DataD [] TMP.D [KindedTV t_6989586621679027167 (ConT TMP.T)] Nothing
[GadtC [TMP.D1] [] (AppT (ConT TMP.D) (ConT TMP.T1))
,GadtC [TMP.D2] [] (AppT (ConT TMP.D) (ConT TMP.T2))
,ForallC [KindedTV d_6989586621679027168 (ConT TMP.T)] [] (GadtC [TMP.D3] [] (AppT (ConT TMP.D) (VarT d_6989586621679027168)))
,GadtC [TMP.D4] [] (AppT (ConT TMP.D) (ConT TMP.T1))] [])
I with a bit of pattern matching - you can find the constructors that have either no restriction (ForallC) or a certain type (TMP.T1/TMP.T2) and then write some expression - to create a new type from those.
Right now I don't have enough time to supply that - but I will update this answer tonight.
EDIT
I looked some more at constructing types, but I have to admit I am a bit stuck myself - I deconstructed the type info kind of successfully.
d = reify ''D
dataName :: Info -> Maybe [Name]
dataName (TyConI (DataD _ _ _ _ x _) )= Just [t | NormalC t _ <- x]
dataName _ = Nothing
gadtDataUnsafe :: Info -> Q Exp
gadtDataUnsafe (TyConI (DataD _ _ _ _ cons _)) = return $ head $ concat [t | GadtC t _ _ <- cons]
I think it is doable to filter the T1/T2/forall d from here, tedious but doable to construct the lists.
What I failed at, is constructing the type - if I load the file into ghci I can execute
> f = $(gadtDataUnsafe =<< d)
>:t f
f :: D 'T1
but if I call that within the file I get the following error
error:
• GHC stage restriction:
‘gadtData’ is used in a top-level splice, quasi-quote, or annotation,
and must be imported, not defined locally
• In the untyped splice: $(gadtData =<< d)
I know that for example Edward Kmett makes some th-magic creating lenses for stuff and there it works inside the same file, but the splice is not assigned to a variable - so maybe you need to construct the names for your lists inside the Q Exp - I guess mkName would be something you need there.
This concludes everything I found out - I hope it helps, I at least learnt a few things - for a full answer maybe someone smarter/more experienced with template haskell can supply some of his/her knowledge in a second answer.

newtype Int -> CInt marshaller

I'm writing FFI to pdflib. Pdflib C API has lots of functions that return and/or take various handles (document, page, image, font) as plain Integer (not pointer).
In order to ensure i do not accidentally pass the wrong param to a function i create a bunch of newtypes in the form of:
newtype PdiDoc = PdiDoc Int
newtype PdiPage = PdiPage Int
newtype PdfImage = PdfImage Int
newtype PdfFont = PdfFont Int
Now i need to provide a marshaller for those types.
image2c (PdfImage i) = fromIntegral i
font2c (PdfFont f) = fromIntegral f
pdipage2c (PdiPage i) = fromIntegral i
As you see the marshallers are exactly the same, just for different types.
So my question is, is there some kind of type magic, SYB vodoo trick that i can use to have just one function to marshall all those types, or do i have to write same functions again and again for different newtypes ?
EDIT: I accepted Don's answer, because it solved my problem.
I switched on
GeneralizedNewtypeDeriving
added
deriving (Eq, Ord, Num, Enum, Real, Integral)
to each of my newtypes, and now i can use standard fromIntegral to marshall all of them.
Nathan Howell's answer is also correct one, i upvoted it. But unfortunately his solution would mean giving up on FFI preprocessors like c2hs i am using.
GHC's FFI extensions allow using newtypes that wrap FFI primitives. You could change the imported function signatures to use the newtypes and (hopefully) avoid having to unwrap them manually.
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
newtype Foo = Foo Int
foreign import ccall someCall :: Foo -> IO Foo
main :: IO ()
main = do
Foo x <- someCall (Foo 1)
print x
Alternatively, the new GHC Generics functionality (available since 7.2.1) allows generic unpacking and repacking of newtypes:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE TypeFamilies #-}
module Main where
import GHC.Generics
-- use a regular newtype
newtype Foo1 = Foo1 Int deriving (Generic, Show)
-- or with record syntax
newtype Foo2 = Foo2{foo2 :: Int} deriving (Generic, Show)
unpack :: (Generic a, Rep a ~ D1 dc (C1 cc (S1 sc (K1 R kc)))) => a -> kc
unpack = unK1 . unM1 . unM1 . unM1 . from
pack :: (Generic a, Rep a ~ D1 dc (C1 cc (S1 sc (K1 R kc)))) => kc -> a
pack = to . M1 . M1 . M1 . K1
-- the C import uses Ints
foreign import ccall "someCall" c'someCall :: Int -> IO Int
-- and the typed wrapper packs/unpacks to FFI primitives
someCall :: Foo1 -> IO Foo2
someCall = fmap pack . c'someCall . unpack
main :: IO ()
main = do
Foo2 x <- someCall (Foo1 1)
print x
You can derive 'Num' for your types using GeneralizedNewtypeDeriving, this helps you a bit with literals and operators.
For the marshalling, I'd use a FFI preprocess, such as hsc2hs, which can automate the wrapping and unwrapping of newtypes.
An example from RWH:

Resources