[Haskell-cafe] Is it possible to get the selector functions when defining a generic class?

Andres Loeh mail at andres-loeh.de
Thu Nov 24 19:51:55 UTC 2016


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 <chris at kahn.pro> wrote:
> 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 <chris at kahn.pro> 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,  <chris at kahn.pro> 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.


More information about the Haskell-Cafe mailing list