Creating a list of valid constructors - haskell

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.

Related

Automatically detect whether a Haskell function is tail recursive

I'm currently writing an auto-grader for a Haskell course. For the section on "tail-recursion", I need a way to automatically and safely detect whether a given Haskell function is tail-recursive or not.
I've searched for existing tools but couldn't find anything. I assume there must be a way to do this automatically, because after all that's what the Haskell compiler does for us. The method doesn't have to be in a specific language or anything since the grader is an external entity in the project. For example, it can be a Haskell library, a command line tool, or code written in any other language (C, Java, Python, etc).
If there actually isn't any such tools, I assume I'm gonna have to use something like a lexical analyzer for Haskell, and write custom code that detects tail recursion myself.
I would first point out that tail recursion is rarely a virtue in Haskell. It's fine if you want to use Haskell as a medium for teaching tail recursion, but actually writing tail recursive functions in Haskell is usually misguided.
Presuming you still want to do this, I would highlight
after all that's what the Haskell compiler does for us
Yes, indeed. So why would any tool other than the compiler exist? The compiler already does exactly this. So, when you want to do this, use the compiler. I'm sure it won't be trivial, because you'll have to learn the compiler's types and other API. But it will actually be correct.
I would start by looking at a function like isAlwaysTailCalled, and see if that does what you want. If it doesn't, maybe you need to consume the AST of the function definition.
I basically agree with amalloy, however for this auto-grader (which presumably should only be a quick way to weed out clear-cut mistakes, not a complete reliable certification tool) I would just cobble something together in Template Haskell.
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE LambdaCase #-}
module TailRecCheck where
import Language.Haskell.TH
isTailRecursive :: Dec -> Bool
isTailRecursive (FunD fName clauses) = all isClauseTR clauses
where
isClauseTR (Clause _ (NormalB (AppE f x)) _)
-- Function application that could be a tail call
= case f of
-- It's only a tail call if the function is the
-- one we're currently defining, and if the rest
-- is not recursive
VarE fn -> fn==fName && isConstant x
-- Constant expressions are allowed as base cases
isClauseTR (Clause _ (NormalB body) _) = isConstant body
--isClauseTR _ ... _ = ...
isConstant (VarE n) = n /= fName
isConstant (ConE _) = True
isConstant (LitE _) = True
isConstant (AppE f x) = isConstant f && isConstant x
isConstant (InfixE l op r)
= all isConstant l && isConstant op && all isConstant r
--isConstant ... = ...
assertTailRecursiveDefs :: Q [Dec] -> Q [Dec]
assertTailRecursiveDefs n = n >>= mapM`id`\case
dec
| isTailRecursive dec -> return dec
| otherwise -> fail ("Function "++showName dec
++" is not tail recursive.")
where showName (FunD n _) = show n
To be used like
{-# LANGUAGE TemplateHaskell #-}
module TailRecCheckExample where
import TailRecCheck
assertTailRecursiveDefs [d|
f x = 4
g 0 = 1
g x = g (x-1)
h 0 = 1
h x = 1 + h (x-1)
|]
TailRecCheckExample.hs:7:1: error:
Function h_6989586621679042356 is not tail recursive.
|
7 | assertTailRecursiveDefs [d|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^...

Creating a result piecewise from stateful computation, with good ergonomics

I'd like to write a function
step :: State S O
where O is a record type:
data O = MkO{ out1 :: Int, out2 :: Maybe Int, out3 :: Maybe Bool }
The catch is that I'd like to assemble my O output piecewise. What I mean by that, is that at various places along the definition of step, I learn then and there that e.g. out2 should be Just 3, but I don't know in a non-convoluted way what out1 and out3 should be. Also, there is a natural default value for out1 that can be computed from the end state; but there still needs to be the possibility to override it in step.
And, most importantly, I want to "librarize" this, so that users can provide their own S and O types, and I give them the rest.
My current approach is to wrap everything in a WriterT (HKD O Last) using Higgledy's automated way of creating a type HKD O Last which is isomorphic to
data OLast = MkOLast{ out1' :: Last Int, out2' :: Last (Maybe Int), out3' :: Last (Maybe String) }
This comes with the obvious Monoid instance, so I can, at least morally, do the following:
step = do
MkOLast{..} <- execWriterT step'
s <- get
return O
{ out1 = fromMaybe (defaultOut1 s) $ getLast out1'
, out2 = getLast out2'
, out3 = fromMaybe False $ getLast out3'
}
step' = do
...
tell mempty{ out2' = pure $ Just 42 }
...
tell mempty{ out1' = pure 3 }
This is code I could live with.
The problem is that I can only do this morally. In practice, what I have to write is quite convoluted code because Higgledy's HKD O Last exposes record fields as lenses, so the real code ends up looking more like the following:
step = do
oLast <- execWriterT step'
s <- get
let def = defaultOut s
return $ runIdentity . construct $ bzipWith (\i -> maybe i Identity . getLast) (deconstruct def) oLast
step' = do
...
tell $ set (field #"out2") (pure $ Just 42) mempty
...
tell $ set (field #"out3") (pure 3) mempty
The first wart in step we can hide away behind a function:
update :: (Generic a, Construct Identity a, FunctorB (HKD a), ProductBC (HKD a)) => a -> HKD a Last -> a
update initial edits = runIdentity . construct $ bzipWith (\i -> maybe i Identity . getLast) (deconstruct initial) edits
so we can "librarize" that as
runStep
:: (Generic o, Construct Identity o, FunctorB (HKD o), ProductBC (HKD o))
=> (s -> o) -> WriterT (HKD o Last) (State s) () -> State s o
runStep mkDef step = do
let updates = execWriterT step s
def <- gets mkDef
return $ update def updates
But what worries me are the places where partial outputs are recorded. So far, the best I've been able to come up with is to use OverloadedLabels to provide #out2 as a possible syntax:
instance (HasField' field (HKD a f) (f b), Applicative f) => IsLabel field (b -> Endo (HKD a f)) where
fromLabel x = Endo $ field #field .~ pure x
output :: (Monoid (HKD o Last)) => Endo (HKD o Last) -> WriterT (HKD o Last) (State s) ()
output f = tell $ appEndo f mempty
this allows end-users to write step' as
step' = do
...
output $ #out2 (Just 42)
...
output $ #out3 3
but it's still a bit cumbersome; moreover, it uses quite a lot of heavy machinery behind the scenes. Especially given that my use case is such that all the library internals would need to be explained step-by-step.
So, what I am looking for are improvements in the following areas:
Simpler internal implementation
Nicer API for end-users
I'd be happy with a completely different approach from first principles as well, as long as it doesn't require the user to define their own OLast next to O...
The following is not a very satisfactory solution because it's still complex and the type errors are horrific, but it tries to achieve two things:
Any attempt to "complete" the construction of the record without having specified all mandatory fields results in a type error.
"there is a natural default value for out1 that can be computed from the end state; but there still needs to be the possibility to override it"
The solution does away with the State monad. Instead, there's an extensible record to which new fields are progressively added—therefore changing its type—until it is "complete".
We use the red-black-record, sop-core (these for HKD-like functionality) and transformers (for the Reader monad) packages.
Some necessary imports:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
import Data.RBR (Record,unit,FromRecord(fromRecord),ToRecord,RecordCode,
Productlike,fromNP,toNP,ProductlikeSubset,projectSubset,
FromList,
Insertable,Insert,insert) -- from "red-black-record"
import Data.SOP (I(I),unI,NP,All,Top) -- from "sop-core"
import Data.SOP.NP (sequence_NP)
import Data.Function (fix)
import Control.Monad.Trans.Reader (Reader,runReader,reader)
import qualified GHC.Generics
The datatype-generic machinery:
specify :: forall k v t r. Insertable k v t
=> v -> Record (Reader r) t -> Record (Reader r) (Insert k v t)
specify v = insert #k #v #t (reader (const v))
close :: forall r subset subsetflat whole . _ => Record (Reader r) whole -> r
close = fixRecord #r #subsetflat . projectSubset #subset #whole #subsetflat
where
fixRecord
:: forall r flat. (FromRecord r, Productlike '[] (RecordCode r) flat, All Top flat)
=> Record (Reader r) (RecordCode r)
-> r
fixRecord = unI . fixHelper I
fixHelper
:: forall r flat f g. _
=> (NP f flat -> g (NP (Reader r) flat))
-> Record f (RecordCode r)
-> g r
fixHelper adapt r = do
let moveFunctionOutside np = runReader . sequence_NP $ np
record2record np = fromRecord . fromNP <$> moveFunctionOutside np
fix . record2record <$> adapt (toNP r)
specify adds a field to an extensible HKD-like record where each field is actually a function from the completed record to the type of the field in the completed record. It inserts the field as a constant function. It can also override existing default fields.
close takes an extensible record constructed with specify and "ties the knot", returning the completed non-HKD record.
Here's code that must be written for each concrete record:
data O = MkO { out1 :: Int, out2 :: Maybe Int, out3 :: Maybe Bool }
deriving (GHC.Generics.Generic, Show)
instance FromRecord O
instance ToRecord O
type ODefaults = FromList '[ '("out1",Int) ]
odefaults :: Record (Reader O) ODefaults
odefaults =
insert #"out1" (reader $ \r -> case out2 r of
Just i -> succ i
Nothing -> 0)
$ unit
In odefaults we specify overrideable default values for some fields, which are calculated by inspecting the "completed" record (this works because we later tie the knot with close.)
Putting it all to work:
example1 :: O
example1 =
close
. specify #"out3" (Just False)
. specify #"out2" (Just 0)
$ odefaults
example2override :: O
example2override =
close
. specify #"out1" (12 :: Int)
. specify #"out3" (Just False)
. specify #"out2" (Just 0)
$ odefaults
main :: IO ()
main =
do print $ example1
print $ example2override
-- result:
-- MkO {out1 = 1, out2 = Just 0, out3 = Just False}
-- MkO {out1 = 12, out2 = Just 0, out3 = Just False}
Here's what I am currently using for this: basically the same Barbies-based technique from my original question, but using barbies-th and lens to create properly named field lenses.
I am going to illustrate it with an example. Suppose I want to collect this result:
data CPUOut = CPUOut
{ inputNeeded :: Bool
, ...
}
Create Barbie for CPUOut using barbies-th, add _ prefix to field names, and use lens's makeLenses TH macro to generate field accessors:
declareBareB [d|
data CPUOut = CPUOut
{ _inputNeeded :: Bool
, ...
} |]
makeLenses ''CPUState
Write update s.t. it works on partial values that are wrapped in the Barbie newtype wrapper:
type Raw b = b Bare Identity
type Partial b = Barbie (b Covered) Last
update
:: (BareB b, ApplicativeB (b Covered))
=> Raw b -> Partial b -> Raw b
update initials edits =
bstrip $ bzipWith update1 (bcover initials) (getBarbie edits)
where
update1 :: Identity a -> Last a -> Identity a
update1 initial edit = maybe initial Identity (getLast edit)
The role of the Barbie wrapper is that Barbie b f has a Monoid instance if only all the fields of b f are monoids themselves. This is exactly the case for Partial CPUOut, so that is what we are going to be collecting in our WriterT:
type CPU = WriterT (Partial CPUOut) (State CPUState)
Write the generic output assignment combinator. This is what makes it nicer than the approach in the original question, because the Setter's are properly named field accessor lenses, not overloaded labels:
(.:=)
:: (Applicative f, MonadWriter (Barbie b f) m)
=> Setter' (b f) (f a) -> a -> m ()
fd .:= x = scribe (iso getBarbie Barbie . fd) (pure x)
Example use:
startInput :: CPU ()
startInput = do
inputNeeded .:= True
phase .= WaitInput

In this case, is it possible to fold Applicative <*> to avoid repetition?

In the following code
module Main where
import Control.Monad.State
import Control.Applicative
type Code = String
toSth :: Read a => State [Code] a
toSth = state $ \(c:cs) -> ((read c), cs)
codes = ["12", "True", ""]
data Tick = Tick {n :: Int, bid :: Bool} deriving (Show)
res = runState (pure Tick <*> toSth <*> toSth) codes
main = print res
I get the correct results
(Tick {n = 12, bid = True},[""])
But my problem is with the repetition of
pure Tick <*> toSth <*> toSth
I.e., if the record has 100 fields, then I have to write <*> toSth 100 times, which does not look Haskell.
Is there a way to foldl on <*>? I know the standard foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b won't work here, because the accumulator type changes in each iteration.
Thanks a lot!
This can be done with some advanced generics libraries, like generics-sop.
Generics libraries translate datatypes from and to some kind of "uniform" representation. The libraries also provide functions to create or modify such representation. We can work over the representation and afterwards transform back into the original datatype.
{-# language DeriveGeneric, TypeApplications #-}
import qualified GHC.Generics
import Generics.SOP (Generic,to,SOP(SOP),NS(Z),hsequence,hcpure)
import Data.Proxy
data Tick = Tick {n :: Int, bid :: Bool} deriving (Show,GHC.Generics.Generic)
instance Generic Tick -- this Generic is from generics-sop
res :: (Tick, [Code])
res =
let tickAction :: State [Code] Tick
tickAction = to . SOP . Z <$> hsequence (hcpure (Proxy #Read) toSth)
in runState tickAction codes
hcpure creates an n-ary product out of an effectful function (here toSth) that knows how to create every member of the product. We have to pass a Proxy with the constraint to convince the compiler. The result is a product where each component is wrapped in State.
hsequence is like sequenceA but for n-ary products having different types for each component. The result is similar: the Applicative is "pulled outwards".
SOP and Z are constructors that wrap the product and let us call to to get a value of the original Tick type.
res could be given this more general signature to work over any single-constructor record that is an instance of Generics.SOP.Generic:
{-# language DataKinds #-}
res :: (Generic r, Generics.SOP.Code r ~ '[ xs ], Generics.SOP.All Read xs) => (r,[Code])
res =
let tickAction = to . SOP . Z <$> hsequence (hcpure (Proxy #Read) toSth)
in runState tickAction codes

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.

Accessing record name and function in generics

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"]

Resources