-
Notifications
You must be signed in to change notification settings - Fork 36
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
How is it possible to discharge Show instance of Sigma? #579
Comments
Yeah, this is admittedly somewhat unsatisfactory. I adapted the implementation of forall a. Show (f a) In the case of singleton types, In the case of sigma types, however, type instance Apply Id '() = () But note that if you change this code such that it no longer scrutinizes the second argument: type instance Apply Id _ = () Then
But yes, this is rather limited in practice, since most type families will actually want to scrutinize the argument in some way, thereby defeating this trick. Sadly, I don't know of another way to define this |
Is this a necessary restriction? type WithDict c = forall r. (c => r) -> r
class ConstraintFromSing c k t where
constraintFromSing :: Proxy c -> Sing (a :: k) -> WithDict (c (t @@ fst)) The - instance (ShowSing s, ShowApply t) => Show (Sigma s t) where
+ instance (ShowSing s, ConstraintFromSing Show s t) => Show (Sigma s t) where
showsPrec p ((a :: Sing (fst :: s)) :&: b) = showParen (p >= 5) $
+ constraintFromSing (Proxy @Show) a $
showsPrec 5 a . showString " :&: " . showsPrec 5 b
:: ShowApply' t fst => ShowS while the definition of instance c (t @@ '()) => ConstraintFromSing c () t where
constraintFromSing _ MkSUnit cont = cont This generalizes to other singleton types, I believe, e.g. instance (c (t @@ True), c (t @@ False)) => ConstraintFromSing c Bool t where
constraintFromSing _ STrue cont = cont
constraintFromSing _ SFalse cont = cont I haven't tried to compile any of the above, but it might work. |
That's quite clever. A bit of shame that we'd need to derive an instance of yet another type class for everything, but perhaps that can't be helped. (Unless there's a way to define |
Ah, it seems that it can work even if data Foo (a :: ()) where
MkFoo :: Foo '()
type FooT :: () ~> Type
data FooT t = MkFooT
instance Show (Foo a) where
show MkFoo = "MkFoo"
type instance Apply FooT t = Foo t
mySigma :: Sigma () FooT
mySigma = MkSUnit :&: MkFoo
example = show mySigma |
Well, technically |
Instead of |
I see, fair enough, in which case the key is to return something with a universal |
Oh, that is an interesting idea. Can you write out a full
I'm not sure what you mean here. Can you elaborate a bit more? |
Yes, you can do this: class MyShow a where
myshow :: a -> String
class c (f @@ i) => CApply c f i where
instance c (f @@ i) => CApply c f i where
instance
forall t f.
(ShowSing t, forall (a :: t). SingI a => CApply MyShow f a) =>
MyShow (Sigma t f) where
myshow ((s :: Sing i) :&: f) =
show s ++ " " ++ withSingC @_ @(CApply MyShow f) @i s (myshow f)
withSingC ::
forall t c i r.
(forall (a :: t). SingI a => c a) =>
Sing i ->
(c i => r) ->
r
withSingC = withSingI At work we don't use type Some :: forall (t :: Type). (t -> Type) -> Type
data Some f where Some :: SingI i => f i -> Some f
instance (forall i. SingI i => Show (f i)) => Show (Some f) where
show (Some f) = show f
The problem with the quantified constraint, that GHC14822 would fix, is that it's really hard to dispatch the In cases where data SBool (i :: Bool) where
STrue :: SBool True
SFalse :: SBool False
type family G i where
G True = () -- Doesn't really matter what these are
G False = ()
newtype GN i = MkGN (G i)
-- "Incorrect" Show instance
deriving instance Show (G i) => Show (GN i)
newtype GN2 i = MkGN2 (G i)
-- "Correct" Show instance
instance SingI i => Show (GN2 i) where
show = error "This can be derived using Generic. Not bothering here."
type instance Sing = SBool
instance SingI True where sing = STrue
instance SingI False where sing = SFalse
-- I can recover the "correct" context.
showGN :: forall (i :: Bool). SingI i => GN i -> String
showGN = case sing @i of
STrue -> show
SFalse -> show
example1 :: Some GN
example1 = Some (MkGN () :: GN True)
-- There's no way of recovering the "correct" context here
-- Could not deduce (Show (G i)) arising from a use of ‘show’
-- example2 :: String
-- example2 = show example1
example3 :: Some GN2
example3 = Some (MkGN2 () :: GN2 True)
example4 :: String
example4 = show example3 |
Ah, I see what you mean now. Indeed, if you used a
Since the quantified constraint requires |
Consider the program below. I think it's uncontroversial (although there's a possibility that I've misunderstood how
Apply
instances are supposed to be written). This is probably the simplest possible program of this sort, yet I don't see how I canshow mySigma
.The error message mentions
Show (Apply Id x)
but what it really wants isforall (x :: ()). Show (Apply Id x)
(viaShowApply
/ShowApply'
). I don't see how that can possibly be discharged.Is there an example somewhere showing how this
Show
instance is supposed to be used in practice?The text was updated successfully, but these errors were encountered: