Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConstraintsT applied to type parameter? #34

Open
sellout opened this issue Nov 14, 2020 · 2 comments
Open

ConstraintsT applied to type parameter? #34

sellout opened this issue Nov 14, 2020 · 2 comments

Comments

@sellout
Copy link

sellout commented Nov 14, 2020

I have a simple case that I can't seem to define (or derive) a ConstraintsT instance for:

data Foo f a = Foo (f a) deriving (Generic)

instance FunctorT Foo

The problem is the f a. The example in the docs (thank you for even having examples!) using T at https://hackage.haskell.org/package/barbies-2.0.1.0/docs/Data-Functor-Transformer.html#g:8 doesn't use a at all. I can't see how you could possibly specify a c a constraint in the AllT type.

Currently we have a bunch of in-house type classes that are similar to what's offered by barbies, and we're trying to get rid of them. Our in-house approach works, but it doesn't separate the constraints from the operations. E.g., we have something like

class FunctorTC (c :: Type -> Constraint) h where
  tmapC :: c b => (forall a. c a => f a -> g a) -> h f b -> h g b

The environment transformer, data EnvT e w a = EnvT e (w a) is another example, and we have a few other internal types that also follow the same pattern.

I've managed a workaround by adding a type parameter to AddT and having taddDicts pass x for that, allowing you to optionally specify c x when you define AddT for your instance:

class FunctorT t => ConstraintsT (t :: (kl -> *) -> kr -> *) where
  type AllT (c :: k -> Constraint) t (x :: kr) :: Constraint
  taddDicts :: forall c f x . AllT c t x => t f x -> t (Dict c `Product` f) x

instance ConstraintsT Foo where
  type AllT c Foo x = c x
  taddDicts (Foo fa) = Foo (Pair Dict fa)

However, that doesn't fully solve things in my case. The next step is a GADT, like

data Goo :: (Type -> Type) -> Type -> Type where
  Cmp :: Ord a => f a -> f a -> Goo f Bool

where it can't find an instance for c a, and I don't even know where to begin on this one.

@jcpetruzza
Copy link
Owner

Thinking out loud (sorry I don't have time to try it out myself at the moment), maybe you could you define your types to be barbies instead, and then use Barbies.Bi.Flip to get the transformers interface you want? Something along the lines of

data FooB a f = FooB (f a)
  deriving (Generic, FunctorB, ConstraintsB)

type Foo = Flip FooB

@sellout
Copy link
Author

sellout commented Nov 14, 2020

Hrmm, I might be able to do something like that. The data type is also a pattern functor for recursion schemes, so it's used like

newtype HFix f a = HFix {hunfix :: f (HFix f) a}

instance FunctorT f => Recursive (NaturalTransformation (->)) (HFix f) where
  cata alg = alg . NT (tmap (cata alg)) . NT hunfix

type GooTree = HFix Goo

So in that instance, I don't have access to either type parameter. But perhaps something like

instance (forall a. FunctorB (Flip f a)) => Recursive (NaturalTransformation (->)) (HFix f) where
  cata alg = alg . NT (bmap (cata alg) . Flip) . NT hunfix

could work.

I'll give it a try. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants