Closed silky closed 9 months ago
Maybe this part of the documentation is relevant - https://hackage.haskell.org/package/barbies-2.0.0.0/docs/Barbies.html#g:3 - but the example doesn't compile, and the link to "see more" is empty 😅
data Person f
newtype Dependants f' f
= Dependants { getDependants :: f' [Person f] }
deriving (Generic)
instance Functor f' => FunctorB (Dependants f')
instance FunctorT Dependants
-- type Dependants f = Dependants f f
<interactive>:4:34: error:
• Couldn't match kind ‘*’ with ‘k0 -> *’
Expected kind ‘(k0 -> *) -> *’, but ‘Dependants f'’ has kind ‘* -> *’
• In the first argument of ‘FunctorB’, namely ‘(Dependants f')’
In the instance declaration for ‘FunctorB (Dependants f')’
Solved:
newtype Thing (f :: * -> *) = Thing { getThing :: [f Int] }
deriving (Generic, Typeable)
instance FunctorB Thing
deriving instance (Show (f Int)) => Show (Thing f)
deriving instance (Eq (f Int)) => Eq (Thing f)
data A' f' f = A
{ name :: f' String
, thing :: f' (Thing f) }
deriving (Generic)
instance FunctorT A'
instance Functor f' => FunctorB (A' f')
deriving instance (Show (Thing f), Show (f' (Thing f)), Show (f' String)) => Show (A' f' f)
type A f = A' f f
a :: A Identity
a = A (pure "name") (pure $ Thing [pure 1, pure 2, pure 3])
b :: A Maybe
b = btmap1 (Just . runIdentity) a
The trouble is that only works at one level, if you then go and embed A'
in another barbie in a similar style things break again:
newtype Thing (f :: * -> *) = Thing { getThing :: [f Int] }
deriving (Generic, FunctorB)
deriving instance (Show (f Int)) => Show (Thing f)
data A' f' f = A
{ name :: f' String
, thing :: f' (Thing f)
}
deriving (Generic)
instance FunctorT A'
instance Functor f' => FunctorB (A' f')
deriving instance (Show (f' (Thing f)), Show (f' String)) => Show (A' f' f)
newtype B' f'' f' f = B
{ someA :: f'' (A' f' f)
}
deriving Generic
type A f = A' f f
type B f = B' f f f
a :: A Identity
a = A (pure "name") (pure $ Thing [pure 1, pure 2, pure 3])
a' :: A Maybe
a' = btmap1 (Just . runIdentity) a
--b :: B Identity
--b = B a
The trouble is how to define the FunctorT/B instances; it just doesn't seem there's a way.
instance FunctorT B'
is clearly wrong, as B'
has the wrong kind.
What are the options here?
Thanks!
Hi @silky, sorry for the late reply. As you probably noticed, it is not possible to have a FunctorB instance for something like:
data Foo f = Foo (f [f Int]))
This is not a limitation of the library, but it's just not possible to write a manual instance either. If you try, you'll end up wth something similar to:
instance FunctorB Foo where
bmap h (Foo ffis) = Foo (h <$> h ffis) -- doesn't work since h :: (forall x. f a -> g a), and you don't have a Functor instance for g
If you only need one level of this, then using btmap1, as you saw, does the trick. But this doesn't generalize to more levels.
edit: removed alternative suggestion that wouldn't really work
Thanks for the response @jcpetruzza .
I'm revisiting this now and still looking around for an answer :) I tried barbies-layered but I didn't have much luck (there's no default bmap
implementation and I wasn't sure what to write); now looking at the hypertypes library.
Would be lovely if there was a solution :)
As I said, I don't think you'll be able to make this work given the type of bmap
.
One could define a different class hierarchy, e.g one where bmap
requires a Functor
constraint on the input or the output, and you'd be able to define your instances there, but that'd come with other trade-offs.
I'm having trouble trying to wrap a barbie in a barbie, I think; but to me it's something htat seems pretty reasonable.
Consider:
There is a type-error on the
Covered
instance:I'm not too sure how to go about solving this. Any advice would be appreciated!
Some more context: https://discourse.haskell.org/t/trouble-with-barbies/8344/4