Open bgamari opened 10 years ago
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.
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
.
I may take a bit to merge this one, but I'm sold on the general idea.
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
.
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 notifications@github.comwrote:
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 .
@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.
@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?
@sjoerdvisscher oh dear, I completely overlooked your mention of introducing Functor
instances for the generic types. Forget about the above.
This is a first cut at deriving
Rep
instances with Template Haskell. Does this interface look sane?