adjunctions icon indicating copy to clipboard operation
adjunctions copied to clipboard

[RFC] Add Data.Functor.Rep.TH

Open bgamari opened this issue 10 years ago • 8 comments

This is a first cut at deriving Rep instances with Template Haskell. Does this interface look sane?

bgamari avatar Apr 02 '14 16:04 bgamari

I should add that @ekmett has suggested using generics for this but I'm a bit too dense to see a way of doing this that provides the same ease of use and safety as the Template Haskell option.

bgamari avatar Apr 02 '14 16:04 bgamari

One open question surrounding this patch is what set of instances the representation type should be equipped with. Currently this set includes Typeable which is a bit unfortunate as it requires -XDeriveDataTypeable.

bgamari avatar Apr 02 '14 17:04 bgamari

I may take a bit to merge this one, but I'm sold on the general idea.

ekmett avatar Apr 02 '14 19:04 ekmett

I would expect the generics based code to look like this:

import qualified GHC.Generics as Gen

class Distributive f => Representable f where
  type Rep f :: *
  type Rep f = Rep (Gen.Rep1 f)

  tabulate :: (Rep f -> a) -> f a
  default tabulate :: (Gen.Generic1 f, Rep (Gen.Rep1 f) ~ Rep f, Representable (Gen.Rep1 f)) => (Rep f -> a) -> f a
  tabulate = Gen.to1 . tabulate

  index    :: f a -> Rep f -> a
  default index :: (Gen.Generic1 f, Rep (Gen.Rep1 f) ~ Rep f, Representable (Gen.Rep1 f)) => f a -> Rep f -> a
  index = index . Gen.from1

and also a lot of instances for Functor, Distributive and Representable for all the GHC.Generics data types except V1 and :+:.

And then you can do

instance Representable A

instead of

deriveRep 'A

But I'd first start with derving instances for Distributive actually. Although Distributive has the problem that all methods already have a default implementation, so when you replace one method with a generic implementation, anyone who doesn't use generics would have to implement that one and would no longer be able to choose between implementing distribute or collect.

sjoerdvisscher avatar Apr 03 '14 21:04 sjoerdvisscher

I'm open to including both GHC.Generics and template-haskell based versions as the former is 'zero touch' for the easy cases and the latter yields nicer representations.

On Thu, Apr 3, 2014 at 5:26 PM, Sjoerd Visscher [email protected]:

I would expect the generics based code to look like this:

import qualified GHC.Generics as Gen

class Distributive f => Representable f where type Rep f :: * type Rep f = Rep (Gen.Rep1 f)

tabulate :: (Rep f -> a) -> f a default tabulate :: (Gen.Generic1 f, Rep (Gen.Rep1 f) ~ Rep f, Representable (Gen.Rep1 f)) => (Rep f -> a) -> f a tabulate = Gen.to1 . tabulate

index :: f a -> Rep f -> a default index :: (Gen.Generic1 f, Rep (Gen.Rep1 f) ~ Rep f, Representable (Gen.Rep1 f)) => f a -> Rep f -> a index = index . Gen.from1

and also a lot of instances for Functor, Distributive and Representablefor all the GHC.Generics data types except V1 and :+:.

And then you can do

instance Representable A

instead of

deriveRep 'A

But I'd first start with derving instances for Distributive actually. Although Distributive has the problem that all methods already have a default implementation, so when you replace one method with a generic implementation, anyone who doesn't use generics would have to implement that one and would no longer be able to choose between implementing distribute or collect.

— Reply to this email directly or view it on GitHubhttps://github.com/ekmett/adjunctions/pull/8#issuecomment-39507018 .

ekmett avatar Apr 03 '14 21:04 ekmett

@sjoerdvisscher, regarding Distributive you might want to have a look at https://github.com/ekmett/distributive/pull/4. It was only after working through this that I realized how one might derive Representable from Generic as you documented. This is now on my to-do list for an idle weekend but it could be a while until such a weekend appears.

bgamari avatar Apr 03 '14 21:04 bgamari

@sjoerdvisscher the trouble with this Generic approach is that you require Representable (Rep1 f) which isn't possible as Rep1 f is not a functor as would be required by the Distributive f class bound. Perhaps you meant GRepresentable (Rep1 f) here?

bgamari avatar Nov 18 '14 18:11 bgamari

@sjoerdvisscher oh dear, I completely overlooked your mention of introducing Functor instances for the generic types. Forget about the above.

bgamari avatar Nov 18 '14 19:11 bgamari