-
Notifications
You must be signed in to change notification settings - Fork 15
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
Expand the Wear type family a bit #28
Comments
I can see why you'd want to do that! Still it feels a bit arbitrary, right? E.g. why stop with As you say, with unsaturated type familes, you'd just write your own type-family and we wouldn't need the class FunctorB (b Covered) => BareWithB bare b where
bstrip :: b Covered Identity -> b bare Identity
bcover :: b bare Identity -> b Covered Identity
type BareB = BareWithB Bare That way, you could define: data MyBare
type family MyWear t f a where
MyWear MyBare f (First a) = a
MyWear MyBare f (Last a) = a
MyWear MyBare f a = a
MyWear Covered f a = f a And then define an |
Wait, would that work without unsaturated TFs? Or are you talking about how to best make use of them? I don't see yet where
yes.. but now that I think of it, there is a neater approach to resolving the arbitrariness: newtype Thin f a = Thin (f a)
-- we don't need/use the constructor, but it helps infer kinds
type family Wear t f a where
Wear Bare f (Thin g a) = a
Wear Bare f a = a
Wear Covered f (Thin g a) = f (g a)
Wear Covered f a = f a
Wear (Param _ t) f a = Wear t f a
Wear t _ _ = TypeError …
-- now my example would become
MyConfig t f = MyConfig
{ a :: Wear t f (Thin Last Bool)
, b :: Wear t f [Text]
} I haven't actually tested this, but I am pretty sure that The |
|
Yeah, sorry I was not very clear. I meant, without unsaturated type families. If we were to relax MyConfig t f = MyConfig
{ a :: MyWear t f (Last Bool)
, b :: MyWear t f [Text]
}
deriving (Generic, FunctorB (MyConfig Covered), BareByB MyBare MyConfig) So by abstracting over In any case, I like your instance repbi ~ repbb => GBare n (Rec repbi repbi) (Rec repbb repbb) where
gstrip _ = id
{-# INLINE gstrip #-}
gcover _ = id
{-# INLINE gcover #-} to become instance Coercible repbi repbb => GBare n (Rec repbi repbi) (Rec repbb repbb) where
gstrip _ = coerce
{-# INLINE gstrip #-}
gcover _ = coerce
{-# INLINE gcover #-} |
Thanks for the quick feedback! |
Reopening since the |
The problem with newtype Sticky f g a = Sticky (f (g a))
-- we don't need/use the constructor, but it helps infer kinds
type family Wear t f a where
Wear Bare (Sticky f g a) = a
Wear Bare f a = a
Wear Covered (Sticky f g a) = f (g a)
Wear Covered f a = f a
Wear (Param _ t) f a = Wear t f a
Wear t _ _ = TypeError …
data MyConfig t f = MyConfig
{ a :: Wear t (Sticky f Last Bool)
, b :: Wear t f [Text]
} I guess we'll need a |
That's a good idea. I assume you mean type family Wear t f a where
Wear Bare (Sticky f g) a = a
Wear Bare f a = a
Wear Covered (Sticky f g) a = f (g a)
Wear Covered f a = f a
Wear (Param _ t) f a = Wear t f a
Wear t _ _ = TypeError …
data MyConfig t f = MyConfig
{ a :: Wear t (Sticky f Last) Bool
, b :: Wear t f [Text]
} I'll try that. |
It does not work out of the box, and I now doubt that it could. Consider the type of bmap :: forall b f g . FunctorB b => (forall a . f a -> g a) -> b f -> b g That is, There is a different approach, that comes back full circle to your "define your own type family" approach, although there is no need to specialise it any specific wrappers. Consider this: type family WearTwo t f g a where
WearTwo Bare f g a = a
WearTwo Covered f g a = f (g a)
WearTwo (Param _ t) f g a = WearTwo t f g a
WearTwo t _ _ _ =
TypeError ( 'Text "`WearTwo` should only be used with "
':<>: 'Text "`Bare` or `Covered`."
':$$: 'Text "`" ':<>: 'ShowType t ':<>: 'Text "`"
':<>: 'Text " is not allowed in this context."
)
data MyConfig t f = MyConfig
{ a :: WearTwo t f Last Bool
, b :: Wear t f [Text]
} I still don't test the full "does the semigroup instance work for this" part, but the shapes of |
I haven't checked, but I think with the I could make a new PR either with the minimum set of changes to allow this, or the full "add the |
This is interesting. If relaxing the generic instance to use |
Yep, I have confirmed that it works. So the |
See #30 (which does include the |
Greetings!
question
Is there any chance to expand the type family like this:
(This also requires two new instances, of course:
)
motivation
use-case is that for combining configs I have
f ~ Option
, and together witha ~ Last X
this gives nice behaviour for generic Semigroup instances. So you'd have adiscussion
We cannot abstract over the type family (yet) so putting this in here is the only way to get this feature, I fear. The downside is that this is a bit confusing behaviour "why does this remove my First/Last wrapper" but then I don't think there are any users who have barbies over First/Last values, apart from this usecase.. it is a bit of a hack.
The text was updated successfully, but these errors were encountered: