Is it possible to get the selector functions when defining a generic class?

Hey all! I'm trying to understand what's going on in GHC.Generics and defining a generic class... I understand that there's a `Selector` class and `selName` function that can get the *name* of a selector, but is there a way to access the selector function itself? The documentation conveniently avoids examples involving records and is otherwise quite barren. So if I have a data type like... data Person = Person { name :: String , age :: Int } deriving Generic instance MyTypeClass Person I want my generic implementation of MyTypeClass to be able to access each selector function in the record, f :: Person -> String, g :: Person -> Int, etc. Chris

Sorry if anyone gets this twice; the first copy somehow went to a
non-existent Google Groups version of haskell-cafe.
GHC.Generics doesn't offer any built-in support for such things. It
*looks* like there *might* be some support in packages built around
generics-sop. When you're working directly with GHC.Generics, the
notion of a record barely even makes sense. A record is seen as simply
a possibly-nested product. For example, ('a','b','c') will look
*approximately* like 'a' :*: ('b' :*: 'c'). You're generally not
"supposed" to care how large a record you may be dealing with, let
alone what field names it has. May I ask what you're actually trying
to do? Your specific request sounds peculiarly un-generic.
On Wed, Nov 23, 2016 at 9:52 PM,
Hey all!
I'm trying to understand what's going on in GHC.Generics and defining a generic class... I understand that there's a `Selector` class and `selName` function that can get the name of a selector, but is there a way to access the selector function itself? The documentation conveniently avoids examples involving records and is otherwise quite barren.
So if I have a data type like...
data Person = Person { name :: String , age :: Int } deriving Generic
instance MyTypeClass Person
I want my generic implementation of MyTypeClass to be able to access each selector function in the record, f :: Person -> String, g :: Person -> Int, etc.
Chris
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Aaaand you'll get mine twice since I forgot to reply-all the first time :) Sure, so in postgresql-simple there are two classes for automatically generating functions that encode/decode database rows, `FromRow` and `ToRow`. In the Hasql library--another postgres library--the encoders and decoders must be written by hand for each user-defined type. I want to write a class that will automatically generate these. I successfully wrote a `FromRow` class that can generate Hasql's `Row` type, since it's basically identical to what's in postgresql-simple's `FromRow`. But in Hasql the encoder type, Params, is contravariant and encoders are defined like: personEncoder :: Params Person personEncoder = contramap name (value text) <> contramap age (value int) The `value text` part can be determined based on the type information, but it's also expecting a matching selector function. I'm at a total loss for how I could generate something like this. On 11/23/2016 10:06 PM, David Feuer wrote:
Sorry if anyone gets this twice; the first copy somehow went to a non-existent Google Groups version of haskell-cafe.
GHC.Generics doesn't offer any built-in support for such things. It *looks* like there *might* be some support in packages built around generics-sop. When you're working directly with GHC.Generics, the notion of a record barely even makes sense. A record is seen as simply a possibly-nested product. For example, ('a','b','c') will look *approximately* like 'a' :*: ('b' :*: 'c'). You're generally not "supposed" to care how large a record you may be dealing with, let alone what field names it has. May I ask what you're actually trying to do? Your specific request sounds peculiarly un-generic.
On Wed, Nov 23, 2016 at 9:52 PM,
wrote: Hey all!
I'm trying to understand what's going on in GHC.Generics and defining a generic class... I understand that there's a `Selector` class and `selName` function that can get the name of a selector, but is there a way to access the selector function itself? The documentation conveniently avoids examples involving records and is otherwise quite barren.
So if I have a data type like...
data Person = Person { name :: String , age :: Int } deriving Generic
instance MyTypeClass Person
I want my generic implementation of MyTypeClass to be able to access each selector function in the record, f :: Person -> String, g :: Person -> Int, etc.
Chris
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Hi Chris.
Here's a proof-of-concept implementation using generics-sop:
https://gist.github.com/kosmikus/83a644fcaa620b5f5505d48540a5f155
It's entirely untested, but it should in principle work, and it should
demonstrate how you can do the contramap/selector stuff generically,
so perhaps it helps.
Cheers,
Andres
On Thu, Nov 24, 2016 at 4:17 AM, Chris Kahn
Aaaand you'll get mine twice since I forgot to reply-all the first time :)
Sure, so in postgresql-simple there are two classes for automatically generating functions that encode/decode database rows, `FromRow` and `ToRow`. In the Hasql library--another postgres library--the encoders and decoders must be written by hand for each user-defined type. I want to write a class that will automatically generate these.
I successfully wrote a `FromRow` class that can generate Hasql's `Row` type, since it's basically identical to what's in postgresql-simple's `FromRow`. But in Hasql the encoder type, Params, is contravariant and encoders are defined like:
personEncoder :: Params Person personEncoder = contramap name (value text) <> contramap age (value int)
The `value text` part can be determined based on the type information, but it's also expecting a matching selector function. I'm at a total loss for how I could generate something like this.
On 11/23/2016 10:06 PM, David Feuer wrote:
Sorry if anyone gets this twice; the first copy somehow went to a non-existent Google Groups version of haskell-cafe.
GHC.Generics doesn't offer any built-in support for such things. It *looks* like there *might* be some support in packages built around generics-sop. When you're working directly with GHC.Generics, the notion of a record barely even makes sense. A record is seen as simply a possibly-nested product. For example, ('a','b','c') will look *approximately* like 'a' :*: ('b' :*: 'c'). You're generally not "supposed" to care how large a record you may be dealing with, let alone what field names it has. May I ask what you're actually trying to do? Your specific request sounds peculiarly un-generic.
On Wed, Nov 23, 2016 at 9:52 PM,
wrote: Hey all!
I'm trying to understand what's going on in GHC.Generics and defining a generic class... I understand that there's a `Selector` class and `selName` function that can get the name of a selector, but is there a way to access the selector function itself? The documentation conveniently avoids examples involving records and is otherwise quite barren.
So if I have a data type like...
data Person = Person { name :: String , age :: Int } deriving Generic
instance MyTypeClass Person
I want my generic implementation of MyTypeClass to be able to access each selector function in the record, f :: Person -> String, g :: Person -> Int, etc.
Chris
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Thanks for this! Seems like that's what I want. I didn't know about generics-sop. Although something about the code for the enumerator types doesn't compile and throws this GHC panic: ghc: panic! (the 'impossible' happened) (GHC version 8.0.1 for x86_64-unknown-linux): print_equality ~ Do you think it's related to this ticket? (https://ghc.haskell.org/trac/ghc/ticket/12041) But at least, when I remove the definitions for enumerated types it compiles, so I'll test it out and see how this is working. On Thu, Nov 24, 2016, at 04:12 AM, Andres Loeh wrote:
Hi Chris.
Here's a proof-of-concept implementation using generics-sop:
https://gist.github.com/kosmikus/83a644fcaa620b5f5505d48540a5f155
It's entirely untested, but it should in principle work, and it should demonstrate how you can do the contramap/selector stuff generically, so perhaps it helps.
Cheers, Andres
On Thu, Nov 24, 2016 at 4:17 AM, Chris Kahn
wrote: Aaaand you'll get mine twice since I forgot to reply-all the first time :)
Sure, so in postgresql-simple there are two classes for automatically generating functions that encode/decode database rows, `FromRow` and `ToRow`. In the Hasql library--another postgres library--the encoders and decoders must be written by hand for each user-defined type. I want to write a class that will automatically generate these.
I successfully wrote a `FromRow` class that can generate Hasql's `Row` type, since it's basically identical to what's in postgresql-simple's `FromRow`. But in Hasql the encoder type, Params, is contravariant and encoders are defined like:
personEncoder :: Params Person personEncoder = contramap name (value text) <> contramap age (value int)
The `value text` part can be determined based on the type information, but it's also expecting a matching selector function. I'm at a total loss for how I could generate something like this.
On 11/23/2016 10:06 PM, David Feuer wrote:
Sorry if anyone gets this twice; the first copy somehow went to a non-existent Google Groups version of haskell-cafe.
GHC.Generics doesn't offer any built-in support for such things. It *looks* like there *might* be some support in packages built around generics-sop. When you're working directly with GHC.Generics, the notion of a record barely even makes sense. A record is seen as simply a possibly-nested product. For example, ('a','b','c') will look *approximately* like 'a' :*: ('b' :*: 'c'). You're generally not "supposed" to care how large a record you may be dealing with, let alone what field names it has. May I ask what you're actually trying to do? Your specific request sounds peculiarly un-generic.
On Wed, Nov 23, 2016 at 9:52 PM,
wrote: Hey all!
I'm trying to understand what's going on in GHC.Generics and defining a generic class... I understand that there's a `Selector` class and `selName` function that can get the name of a selector, but is there a way to access the selector function itself? The documentation conveniently avoids examples involving records and is otherwise quite barren.
So if I have a data type like...
data Person = Person { name :: String , age :: Int } deriving Generic
instance MyTypeClass Person
I want my generic implementation of MyTypeClass to be able to access each selector function in the record, f :: Person -> String, g :: Person -> Int, etc.
Chris
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Hi Chris.
Yes, it's this known issue, which seems to be triggered by partial
applications of (~), and which is fixed in 8.0.2. [It actually
compiles for me with 8.0.1 though. It just happens under certain
circumstances, for example if I ask for the type of gEValue. Strange
that you say you cannot even compile it.]
Here's another workaround that seems to work for me:
class (a ~ b) => Equal a b
instance (a ~ b) => Equal a b
This may require extra language extensions, in particular PolyKinds.
Then replace all three occurrences of ((~) '[]) with (Equal '[]).
I'm not all that certain about the enumeration type generic
definitions anyway, though. There are many different ways in which you
might want to represent an enumeration type in an SQL database table,
so more thought might be required here anyway.
Cheers,
Andres
On Thu, Nov 24, 2016 at 8:19 PM, Chris Kahn
Thanks for this! Seems like that's what I want. I didn't know about generics-sop.
Although something about the code for the enumerator types doesn't compile and throws this GHC panic:
ghc: panic! (the 'impossible' happened) (GHC version 8.0.1 for x86_64-unknown-linux): print_equality ~
Do you think it's related to this ticket? (https://ghc.haskell.org/trac/ghc/ticket/12041)
But at least, when I remove the definitions for enumerated types it compiles, so I'll test it out and see how this is working.
On Thu, Nov 24, 2016, at 04:12 AM, Andres Loeh wrote:
Hi Chris.
Here's a proof-of-concept implementation using generics-sop:
https://gist.github.com/kosmikus/83a644fcaa620b5f5505d48540a5f155
It's entirely untested, but it should in principle work, and it should demonstrate how you can do the contramap/selector stuff generically, so perhaps it helps.
Cheers, Andres
On Thu, Nov 24, 2016 at 4:17 AM, Chris Kahn
wrote: Aaaand you'll get mine twice since I forgot to reply-all the first time :)
Sure, so in postgresql-simple there are two classes for automatically generating functions that encode/decode database rows, `FromRow` and `ToRow`. In the Hasql library--another postgres library--the encoders and decoders must be written by hand for each user-defined type. I want to write a class that will automatically generate these.
I successfully wrote a `FromRow` class that can generate Hasql's `Row` type, since it's basically identical to what's in postgresql-simple's `FromRow`. But in Hasql the encoder type, Params, is contravariant and encoders are defined like:
personEncoder :: Params Person personEncoder = contramap name (value text) <> contramap age (value int)
The `value text` part can be determined based on the type information, but it's also expecting a matching selector function. I'm at a total loss for how I could generate something like this.
On 11/23/2016 10:06 PM, David Feuer wrote:
Sorry if anyone gets this twice; the first copy somehow went to a non-existent Google Groups version of haskell-cafe.
GHC.Generics doesn't offer any built-in support for such things. It *looks* like there *might* be some support in packages built around generics-sop. When you're working directly with GHC.Generics, the notion of a record barely even makes sense. A record is seen as simply a possibly-nested product. For example, ('a','b','c') will look *approximately* like 'a' :*: ('b' :*: 'c'). You're generally not "supposed" to care how large a record you may be dealing with, let alone what field names it has. May I ask what you're actually trying to do? Your specific request sounds peculiarly un-generic.
On Wed, Nov 23, 2016 at 9:52 PM,
wrote: Hey all!
I'm trying to understand what's going on in GHC.Generics and defining a generic class... I understand that there's a `Selector` class and `selName` function that can get the name of a selector, but is there a way to access the selector function itself? The documentation conveniently avoids examples involving records and is otherwise quite barren.
So if I have a data type like...
data Person = Person { name :: String , age :: Int } deriving Generic
instance MyTypeClass Person
I want my generic implementation of MyTypeClass to be able to access each selector function in the record, f :: Person -> String, g :: Person -> Int, etc.
Chris
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (4)
-
Andres Loeh
-
Chris Kahn
-
chris@kahn.pro
-
David Feuer