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

Adam Gundry adam at well-typed.com
Thu Nov 24 08:50:18 UTC 2016


Hi Chris,

With the addition of type-level metadata to GHC.Generics in GHC 8, it's
possible to build a field selector generically. I hacked a rough
implementation together a while back [1]. (This would undoubtedly be
nicer with generics-sop, but I believe the work to adapt it to support
type-level metadata is ongoing.)

It's somewhat unsatisfying that GHC has already got a selector function,
but we can't get at it generically. Depending on the details of your use
case, the HasField class to be introduced as part of the
OverloadedRecordFields work [2] might provide an alternative.

Hope this helps,

Adam

[1] https://gist.github.com/adamgundry/2eea6ca04fd6e5b6e76ce9bfee454a6b
[2] https://github.com/ghc-proposals/ghc-proposals/pull/6


On 24/11/16 03:28, David Feuer wrote:
> I don't know much about this database stuff, but I'm pretty sure you
> want to *build* the selector, rather than *extracting* it. You should
> use the Generics metadata to get the string for parsing/printing, but
> aside from that, you just have the products.
> 
> 
> On Nov 23, 2016 10:19 PM, "Chris Kahn" <chris at kahn.pro
> <mailto: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
>     <mailto: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


-- 
Adam Gundry, Haskell Consultant
Well-Typed LLP, http://www.well-typed.com/


More information about the Haskell-Cafe mailing list