-
Notifications
You must be signed in to change notification settings - Fork 37
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
Make singletons
buildable after GHC#23515
#601
Labels
Comments
RyanGlScott
added a commit
that referenced
this issue
Jun 3, 2024
This makes it clearer what the `Sing` instances are actually matching on. Moreover, this will be required in order to make these instances compile after [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515) is implemented. This resolves the "`Sing` instances without explicit left-hand sides" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 3, 2024
This makes it clearer what the `Sing` instances are actually matching on. Moreover, this will be required in order to make these instances compile after [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515) is implemented. This resolves the "`Sing` instances without explicit left-hand sides" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 3, 2024
After the changes in [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515) are implemented, some `Apply` instances will fail to compile due to their left-hand sides being kind-generalized to something that is more polymorphic than what their right-hand sides will allow. For example, this commonly occurs when generating `Apply` instances for lambda-lifted definitions or declarations whose kinds use visible dependent quantification. We avoid this issue by now generating `Apply` instances with explicit kind arguments (via `TypeApplications`), leveraging the fact that we know what the kinds are (most of the time) during defunctionalization. See the new section of `Note [Defunctionalization game plan], Wrinkle 2: Non-vanilla kinds` for the full details. Resolves the "Defunctionalizing declarations using visible dependent quantification" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 18, 2024
After the changes in [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515) are implemented, some `Apply` instances will fail to compile due to their left-hand sides being kind-generalized to something that is more polymorphic than what their right-hand sides will allow. For example, this commonly occurs when generating `Apply` instances for lambda-lifted definitions or declarations whose kinds use visible dependent quantification. We avoid this issue by now generating `Apply` instances with explicit kind arguments (via `TypeApplications`), leveraging the fact that we know what the kinds are (most of the time) during defunctionalization. See the new section of `Note [Defunctionalization game plan], Wrinkle 2: Non-vanilla kinds` for the full details. Resolves the "Defunctionalizing declarations using visible dependent quantification" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 18, 2024
Previously, the promoted versions of certain `Compose` instances (`Functor`, `Foldable`, etc.) would be overly general due to the fact that `singletons-th` omits instance contexts during promotion. For example, the promoted `Functor` instance for `Compose` was: ```hs instance PFunctor (Compose (f :: k -> Type) (g :: Type -> k)) where ... ``` But this was too general, as `f` and `g` should both be of kind `Type -> Type` instead. The defunctionalization symbols associated with the instances also had a similar problem. This patch annotates each instance with an explicit kind (e.g., `Functor (Compose (f :: Type -> Type) g)` to ensure that the promoted instances also have the intended kind. This is very much in the same spirit as the situation described in `Note [Using standalone kind signatures not present in the base library]` in `Control.Monad.Singletons.Internal`, but for instance declarations instead of class declarations. Resolves the "Overly polymorphic instance methods" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 18, 2024
Previously, the promoted versions of certain `Compose` instances (`Functor`, `Foldable`, etc.) would be overly general due to the fact that `singletons-th` omits instance contexts during promotion. For example, the promoted `Functor` instance for `Compose` was: ```hs instance PFunctor (Compose (f :: k -> Type) (g :: Type -> k)) where ... ``` But this was too general, as `f` and `g` should both be of kind `Type -> Type` instead. The defunctionalization symbols associated with the instances also had a similar problem. This patch annotates each instance with an explicit kind (e.g., `Functor (Compose (f :: Type -> Type) g)` to ensure that the promoted instances also have the intended kind. This is very much in the same spirit as the situation described in `Note [Using standalone kind signatures not present in the base library]` in `Control.Monad.Singletons.Internal`, but for instance declarations instead of class declarations. Resolves the "Overly polymorphic instance methods" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 19, 2024
This makes it clearer what the `Sing` instances are actually matching on. Moreover, this will be required in order to make these instances compile after [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515) is implemented. This resolves the "`Sing` instances without explicit left-hand sides" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 19, 2024
After the changes in [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515) are implemented, some `Apply` instances will fail to compile due to their left-hand sides being kind-generalized to something that is more polymorphic than what their right-hand sides will allow. For example, this commonly occurs when generating `Apply` instances for lambda-lifted definitions or declarations whose kinds use visible dependent quantification. We avoid this issue by now generating `Apply` instances with explicit kind arguments (via `TypeApplications`), leveraging the fact that we know what the kinds are (most of the time) during defunctionalization. See the new section of `Note [Defunctionalization game plan], Wrinkle 2: Non-vanilla kinds` for the full details. Resolves the "Defunctionalizing declarations using visible dependent quantification" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 19, 2024
Previously, the promoted versions of certain `Compose` instances (`Functor`, `Foldable`, etc.) would be overly general due to the fact that `singletons-th` omits instance contexts during promotion. For example, the promoted `Functor` instance for `Compose` was: ```hs instance PFunctor (Compose (f :: k -> Type) (g :: Type -> k)) where ... ``` But this was too general, as `f` and `g` should both be of kind `Type -> Type` instead. The defunctionalization symbols associated with the instances also had a similar problem. This patch annotates each instance with an explicit kind (e.g., `Functor (Compose (f :: Type -> Type) g)` to ensure that the promoted instances also have the intended kind. This is very much in the same spirit as the situation described in `Note [Using standalone kind signatures not present in the base library]` in `Control.Monad.Singletons.Internal`, but for instance declarations instead of class declarations. Resolves the "Overly polymorphic instance methods" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 25, 2024
Previously, `singletons-th` made no effort to track the kinds of local variables when generating lambda-lifted code, instead generating local variable binders with no kind annotations. As a result, GHC would generalize the kinds of these lambda-lifted definitions to things that are way more polymorphic than intended. While this technically works in today's GHC, it won't in a future version of GHC that implements [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515). In general, generating kinds for every local variable would require `singletons-th` to implement something akin to full-blown type inference over the Template Haskell AST, which is not something I am eager to implement. Fortunately, there is a relatively simple approach we can do to alleviate this problem that doesn't require full type inference. In situations where we know the kind of a local variable (e.g., when there is a top-level signature or there is a pattern signature), we record the variable's kind and use it when generating binders for any lambda-lifted definitions that close over the variable. For the full story on how this works, see `Note [Local variables and kind information]` `D.S.TH.Promote.Syntax.LocalVar`. This is not a perfect solution, as there will still be examples of the original problem that won't be covered by this simple approach (see the Note). This approach is still much better than what `singletons-th` was doing before, and I think it's worth using this simple approach even if it doesn't fix 100% of all cases. This patch mostly resolves the "Overly polymorphic lambda-lifting, part 2" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 26, 2024
Previously, `singletons-th` made no effort to track the kinds of local variables when generating lambda-lifted code, instead generating local variable binders with no kind annotations. As a result, GHC would generalize the kinds of these lambda-lifted definitions to things that are way more polymorphic than intended. While this technically works in today's GHC, it won't in a future version of GHC that implements [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515). In general, generating kinds for every local variable would require `singletons-th` to implement something akin to full-blown type inference over the Template Haskell AST, which is not something I am eager to implement. Fortunately, there is a relatively simple approach we can do to alleviate this problem that doesn't require full type inference. In situations where we know the kind of a local variable (e.g., when there is a top-level signature or there is a pattern signature), we record the variable's kind and use it when generating binders for any lambda-lifted definitions that close over the variable. For the full story on how this works, see `Note [Local variables and kind information]` `D.S.TH.Promote.Syntax.LocalVar`. This is not a perfect solution, as there will still be examples of the original problem that won't be covered by this simple approach (see the Note). This approach is still much better than what `singletons-th` was doing before, and I think it's worth using this simple approach even if it doesn't fix 100% of all cases. This patch mostly resolves the "Overly polymorphic lambda-lifting, part 2" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 30, 2024
This adds more explicit `Type -> Type` kind signatures to definitions that would otherwise be kind-generalized to have overly polymorphic kinds: * The kinds of `Asum` and `Msum` (the promoted counterparts to the term-level `asum` and `msum` functions, respectively). * The helper type families generated when promoting the `Alternative` and `MonadPlus` instances for `Data.Functor.Product`. This sort of kind polymorphism isn't observable by users in today's GHC, but it will cause problems later in a future version of GHC that implements [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515). (See #601.) (I should have added these as part of #606 or #607, but I forgot them due to an oversight.)
RyanGlScott
added a commit
that referenced
this issue
Jun 30, 2024
When promoting a class or instance method, we generate a "helper" type family definition that contains the actual implementation of the class or instance method. Prior to this patch, it was possible that the kind of the helper type family could be more polymorphic than desired. For instance, `singletons-th` would promote this: ```hs $(promote [d| type MyApplicative :: (Type -> Type) -> Constraint class Functor f => MyApplicative f where ap :: f (a -> b) -> f a -> f b rightSparrow :: f a -> f b -> f b rightSparrow x y = ap (id <$ x) y |]) ``` To this: ```hs type PMyApplicative :: (Type -> Type) -> Constraint class PMyApplicative f where type Ap (x :: f (a ~> b)) (y :: f a) :: f b type RightSparrow (x :: f a) (y :: f b) :: f b type RightSparrow x y = RightSparrowDefault x y -- The helper type family type RightSparrowDefault :: forall f a b. f a -> f b -> f b type family RightSparrowDefault x y where RightSparrowDefault x y = Ap (IdSym0 <$ x) y ``` Note that GHC would generalize the standalone kind signature of `RightSparrowDefault` to: ```hs type RightSparrowDefault :: forall {k} (f :: k -> Type) (a :: k) (b :: k). f a -> f b -> f b ``` This is more general than intended, as we want `f` to be of kind `Type -> Type` instead. After all, we said as much in the standalone kind signature for `MyApplicative`! This excessive polymorphism doesn't actively cause problems in today's GHC, but they will cause problems in a future version of GHC that implements [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515). (See #601.) This patch resolves the issue by propagating kind information from the class's standalone kind signature (or, in the case of instance declarations, the instance head) to the helper type family declarations. After this patch, we now generate the following kind for `RightSparrowDefault` (as verified by the new `T601a` test case): ```hs type RightSparrowDefault :: forall (f :: Type -> Type) a b. f a -> f b -> f b ``` This piggybacks on machinery that was added in #596 to do most of the heavy lifting. Resolves the "Overly polymorphic promoted class defaults" section of #601.
This was referenced Jun 30, 2024
RyanGlScott
added a commit
that referenced
this issue
Jun 30, 2024
Previously, `singletons-th` made no effort to track the kinds of local variables when generating lambda-lifted code, instead generating local variable binders with no kind annotations. As a result, GHC would generalize the kinds of these lambda-lifted definitions to things that are way more polymorphic than intended. While this technically works in today's GHC, it won't in a future version of GHC that implements [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515). In general, generating kinds for every local variable would require `singletons-th` to implement something akin to full-blown type inference over the Template Haskell AST, which is not something I am eager to implement. Fortunately, there is a relatively simple approach we can do to alleviate this problem that doesn't require full type inference. In situations where we know the kind of a local variable (e.g., when there is a top-level signature or there is a pattern signature), we record the variable's kind and use it when generating binders for any lambda-lifted definitions that close over the variable. For the full story on how this works, see `Note [Local variables and kind information]` `D.S.TH.Promote.Syntax.LocalVar`. This is not a perfect solution, as there will still be examples of the original problem that won't be covered by this simple approach (see the Note). This approach is still much better than what `singletons-th` was doing before, and I think it's worth using this simple approach even if it doesn't fix 100% of all cases. This patch mostly resolves the "Overly polymorphic lambda-lifting, part 2" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jun 30, 2024
When promoting a class or instance method, we generate a "helper" type family definition that contains the actual implementation of the class or instance method. Prior to this patch, it was possible that the kind of the helper type family could be more polymorphic than desired. For instance, `singletons-th` would promote this: ```hs $(promote [d| type MyApplicative :: (Type -> Type) -> Constraint class Functor f => MyApplicative f where ap :: f (a -> b) -> f a -> f b rightSparrow :: f a -> f b -> f b rightSparrow x y = ap (id <$ x) y |]) ``` To this: ```hs type PMyApplicative :: (Type -> Type) -> Constraint class PMyApplicative f where type Ap (x :: f (a ~> b)) (y :: f a) :: f b type RightSparrow (x :: f a) (y :: f b) :: f b type RightSparrow x y = RightSparrowDefault x y -- The helper type family type RightSparrowDefault :: forall f a b. f a -> f b -> f b type family RightSparrowDefault x y where RightSparrowDefault x y = Ap (IdSym0 <$ x) y ``` Note that GHC would generalize the standalone kind signature of `RightSparrowDefault` to: ```hs type RightSparrowDefault :: forall {k} (f :: k -> Type) (a :: k) (b :: k). f a -> f b -> f b ``` This is more general than intended, as we want `f` to be of kind `Type -> Type` instead. After all, we said as much in the standalone kind signature for `MyApplicative`! This excessive polymorphism doesn't actively cause problems in today's GHC, but they will cause problems in a future version of GHC that implements [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515). (See #601.) This patch resolves the issue by propagating kind information from the class's standalone kind signature (or, in the case of instance declarations, the instance head) to the helper type family declarations. After this patch, we now generate the following kind for `RightSparrowDefault` (as verified by the new `T601a` test case): ```hs type RightSparrowDefault :: forall (f :: Type -> Type) a b. f a -> f b -> f b ``` This piggybacks on machinery that was added in #596 to do most of the heavy lifting. Resolves the "Overly polymorphic promoted class defaults" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jul 1, 2024
When promoting a class or instance method, we generate a "helper" type family definition that contains the actual implementation of the class or instance method. Prior to this patch, it was possible that the kind of the helper type family could be more polymorphic than desired. For instance, `singletons-th` would promote this: ```hs $(promote [d| type MyApplicative :: (Type -> Type) -> Constraint class Functor f => MyApplicative f where ap :: f (a -> b) -> f a -> f b rightSparrow :: f a -> f b -> f b rightSparrow x y = ap (id <$ x) y |]) ``` To this: ```hs type PMyApplicative :: (Type -> Type) -> Constraint class PMyApplicative f where type Ap (x :: f (a ~> b)) (y :: f a) :: f b type RightSparrow (x :: f a) (y :: f b) :: f b type RightSparrow x y = RightSparrowDefault x y -- The helper type family type RightSparrowDefault :: forall f a b. f a -> f b -> f b type family RightSparrowDefault x y where RightSparrowDefault x y = Ap (IdSym0 <$ x) y ``` Note that GHC would generalize the standalone kind signature of `RightSparrowDefault` to: ```hs type RightSparrowDefault :: forall {k} (f :: k -> Type) (a :: k) (b :: k). f a -> f b -> f b ``` This is more general than intended, as we want `f` to be of kind `Type -> Type` instead. After all, we said as much in the standalone kind signature for `MyApplicative`! This excessive polymorphism doesn't actively cause problems in today's GHC, but they will cause problems in a future version of GHC that implements [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515). (See #601.) This patch resolves the issue by propagating kind information from the class's standalone kind signature (or, in the case of instance declarations, the instance head) to the helper type family declarations. After this patch, we now generate the following kind for `RightSparrowDefault` (as verified by the new `T601a` test case): ```hs type RightSparrowDefault :: forall (f :: Type -> Type) a b. f a -> f b -> f b ``` This piggybacks on machinery that was added in #596 to do most of the heavy lifting. Resolves the "Overly polymorphic promoted class defaults" section of #601.
RyanGlScott
added a commit
that referenced
this issue
Jul 1, 2024
This adds more explicit `Type -> Type` kind signatures to definitions that would otherwise be kind-generalized to have overly polymorphic kinds: * The kinds of `Asum` and `Msum` (the promoted counterparts to the term-level `asum` and `msum` functions, respectively). * The helper type families generated when promoting the `Alternative` and `MonadPlus` instances for `Data.Functor.Product`. This sort of kind polymorphism isn't observable by users in today's GHC, but it will cause problems later in a future version of GHC that implements [GHC#23515](https://gitlab.haskell.org/ghc/ghc/-/issues/23515). (See #601.) (I should have added these as part of #606 or #607, but I forgot them due to an oversight.)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
GHC#23515 tracks implementing this portion of GHC proposal #425 (Invisible binders in type declarations):
A reasonable change, but one that will nevertheless cause several parts of
singletons
andsingletons-base
to fail to compile. This issue aims to identify all of these sources of breakage and how to fix them.Table of Contents
Sing
instances without explicit left-hand sidesEDIT: This was fixed by #602.
There are places in
singletons
andsingletons-base
that declareSing
instances without specifying what type theSing
instance is for on the left-hand side, e.g.,This will no longer work after GHC#23515 is implemented. Instead, we must write:
The following places in the code will need to be updated:
singletons/singletons/src/Data/Singletons.hs
Line 408 in 7e5c92d
singletons/singletons/src/Data/Singletons.hs
Line 733 in 7e5c92d
singletons/singletons/src/Data/Singletons/Sigma.hs
Line 102 in 7e5c92d
singletons/singletons/tests/ByHand.hs
Line 101 in 7e5c92d
singletons/singletons/tests/ByHand.hs
Line 155 in 7e5c92d
singletons/singletons/tests/ByHand.hs
Line 195 in 7e5c92d
singletons/singletons/tests/ByHand.hs
Line 245 in 7e5c92d
singletons/singletons/tests/ByHand.hs
Line 318 in 7e5c92d
singletons/singletons/tests/ByHand.hs
Line 364 in 7e5c92d
singletons/singletons/tests/ByHand.hs
Line 396 in 7e5c92d
singletons/singletons/tests/ByHand.hs
Line 423 in 7e5c92d
singletons/singletons/tests/ByHand.hs
Line 1042 in 7e5c92d
singletons/singletons/tests/ByHand2.hs
Line 30 in 7e5c92d
singletons/singletons/tests/ByHand2.hs
Line 43 in 7e5c92d
singletons/singletons/tests/ByHand2.hs
Line 57 in 7e5c92d
singletons/singletons-th/src/Data/Singletons/TH/CustomStar.hs
Line 69 in 7e5c92d
singletons/singletons-base/src/Data/Foldable/Singletons.hs
Line 130 in 7e5c92d
singletons/singletons-base/src/Data/Functor/Compose/Singletons.hs
Line 56 in 7e5c92d
singletons/singletons-base/src/Data/Functor/Const/Singletons.hs
Line 78 in 7e5c92d
singletons/singletons-base/src/Data/Functor/Product/Singletons.hs
Line 60 in 7e5c92d
singletons/singletons-base/src/Data/Functor/Sum/Singletons.hs
Line 56 in 7e5c92d
singletons/singletons-base/src/Data/Proxy/Singletons.hs
Line 63 in 7e5c92d
singletons/singletons-base/src/Data/Traversable/Singletons.hs
Line 67 in 7e5c92d
singletons/singletons-base/src/Data/Traversable/Singletons.hs
Line 77 in 7e5c92d
singletons/singletons-base/src/Data/Singletons/Base/TypeError.hs
Line 85 in 7e5c92d
singletons/singletons-base/src/GHC/TypeLits/Singletons/Internal.hs
Line 69 in 7e5c92d
Overly polymorphic lambda-lifting, part 1
EDIT: This should be fixed as of #593.
This code will fail to compile after GHC#23515 is implemented:
singletons/singletons-base/src/Data/Singletons/Base/Instances.hs
Lines 34 to 41 in 7e5c92d
This is because we will promote
foldl
to code that looks something like this:And this will fail with:
The reason this happens is because the kinds of some of these defunctionalization symbols are more polymorphic than we want. For instance, compare the kinds of
LgoSym4
andLgoSym5
:Note that the kind of
LgoSym5
uses visibleforall
s, whereas the kind ofLgoSym4
does not. This actually matters in practice, because when you write this:If we do nothing but look at the left-hand side of the type family instance, we conclude that:
Note that the type variables in
@(b1 ~> [a1] ~> b1)
are not the same as in(LgoSym4 a b ...)
, because nothing in the kind ofLgoSym4
relates the two.Now GHC proceeds to kind-check the right-hand-side against kind
b1 ~> [a1] ~> b1
:But this doesn't work, because
LgoSym5 a b f z0 xs0
has kindb ~> [a] ~> b
, notb1 ~> [a1] ~> b1
! If we were allowed to unifya
/a1
andb
/b1
, then this would kind-check, but this is not possible due to the changes brought on by GHC#23515.I can see two possible ways to fix this:
If we wrote the defunctionalization symbols like this instead:
Then the kinds of all defunctionalization symbols use visible
forall
s, thereby giving GHC enough information to kind-check this program even with the changes brought on by GHC#23515:This is exactly the change proposed in Reduce defunctionalization symbol bloat related to local variables #592. (I think fixing Reduce defunctionalization symbol bloat related to local variables #592 is worth doing independently of this issue, but it's nice to know that it helps here as well).
Generate this code instead:
It should be possible to generate this code without requiring too much cleverness on
singletons-th
's end.Later in the Defunctionalizing declarations using visible dependent quantification section, we will see an example where option (1) won't suffice and where option (2) is required. And later in the Overly polymorphic lambda-lifting, part 2 section, we will see an example where neither option (1) nor option (2) are sufficient.
Overly polymorphic promoted class defaults
EDIT: This issue no longer occurs within
singletons-base
:asum
,msum
, andProduct
instances explicit kind signatures #611, all examples of this issue that occur insingletons-base
now have the necessary standalone kind signatures to allowsingletons-th
to generate more precise code for promoted class defaults.Note that the underlying issue still applies regardless of the changes above, however—you'll still need to provide standalone kind signatures in places that didn't require them before.
Consider this program:
We have not given
MyApplicative
a standalone kind signature, but the intent is thatf
is inferred to be of kindType -> Type
. However, consider what happens whenMyApplicative
is promoted:There's something suspicious about
RightSparrowDefault
. It has the standalone kind signaturef a -> f b -> f b
, and GHC will kind-generalize this toforall {k} (f :: k -> Type) (a :: k) (b :: k). f a -> f b -> f b
. The actual body ofRightSparrowDefault
, however, requiresk
to beType
. GHC does not like this after the changes brought on by GHC#23515, and it will reject it:(This is the same issue described in
Note [Fully saturated defunctionalization symbols]
).It's tempting to try to repair the issue by removing the standalone kind signature:
But GHC won't accept that, regardless of whether you have the changes from GHC#23515 or not:
As such, we're stuck between a rock and a hard place.
Unfortunately, I don't know if
singletons-th
will be able to promote classes likeMyApplicative
anymore—at least, not without making some minor edits to clarify what the kind off
is. My vision is being able to write this instead:And then
singletons-th
would generate this default instead:And then everything would be fine and dandy. Currently,
singletons-th
does not do this, but it could with a bit of additional work to make the(Type -> Type)
kind from the class flow down through to the promoted class method default.Overly polymorphic instance methods
EDIT: I believe all known examples of this issue in
singletons-base
have been worked around in #607 and #611. The underlying issue still applies, however.Just as class defaults can be overly polymorphic, so too can instance methods. Consider this example:
Currently, this instance will be promoted to:
There are two problems with this code:
When GHC kind-checks
FmapCompose
's standalone kind signature, it will kind-generalize it to:This is too general for our needs, as calling
Fmap
requires that bothf
andg
be of kindType -> Type
:GHC will kind-generalize the
instance PFunctor (Compose f g)
declaration to:Which is also too polymorphic:
Again, I think users will need some kind of manual edits in order to make this sort of code work. A workaround exists in today's
singletons-th
which works well enough:This will make
singletons-th
generate code that looks like this:Defunctionalizing declarations using visible dependent quantification
EDIT: This was fixed by #603.
When you promote this type-level declaration:
singletons-th
will generate this code:GHC will now reject this with:
If this feels familiar, it's because we've already seen this exact same scenario play out before in the Overly polymorphic lambda-lifting, part 1 section. In particular, we have defunctionalization symbols with the following kinds:
Note that the kind of
PSym1
uses a visibleforall
, whereas the kind ofPSym0
does not. Therefore, when GHC kind-checks the left-hand side of this type family instance:GHC concludes that:
Where
k1
is distinct fromk
. Therefore, when we kind-check the right-hand side:We have a kind error, as
PSym1 k
has kindk ~> Type
, notk1 ~> Type
. (Note thatk1
happens to be called "arg
" in the error message above.)This time, the trick from #592 (i.e., option (1) in the Overly polymorphic lambda-lifting, part 1 section) won't work, as there is no lambda-lifting happening here. The most viable solution is to implement option (2) in the Overly polymorphic lambda-lifting, part 1 section by generating this code:
Overly polymorphic lambda-lifting, part 2
EDIT: This was fixed by #610.
Neither option (1) nor option (2) from the Overly polymorphic lambda-lifting, part 1 section above are enough to make this example work:
singletons-th
will generate (roughly) the following code when promotingnub
:GHC will now reject this:
The problem is that
Case
's kind is too polymorphic:Rather than something like:
However, we can do better here. Note that none of the arguments to
Case
have any kind signatures whatsoever:This is silly, because we can determine the kinds of several of these arguments (e.g.,
ls
andl
) by looking at the syntax ofnub
. And indeed, if we sprinkle even a couple of these kind signatures into the definition ofCase
:Then GHC accepts the program once more. It should be possible to generate these kind signatures during lambda lifting.
Parts of
singletons-base
which are affected by this issue are:nub
:singletons/singletons-base/src/Data/List/Singletons/Internal.hs
Lines 564 to 569 in 037fc0e
foldMapDefault
:singletons/singletons-base/src/Data/Traversable/Singletons.hs
Lines 298 to 303 in 037fc0e
replicateM
:singletons/singletons-base/src/Control/Monad/Singletons.hs
Lines 206 to 213 in 037fc0e
replicateM_
:singletons/singletons-base/src/Control/Monad/Singletons.hs
Lines 216 to 223 in 037fc0e
Overly polymorphic local bindings
Here is a problematic example, boiled down from the
Singletons/T296.hs
test case:This translates to the following code:
LetZ
is problematic. GHC 9.10.1 accepts it, but gives it a counterintuitive kind:Rather than giving it the kind
forall a -> Maybe a
, it's given the kindType -> Maybe a
, and the type family equation forLetZ
matches on the invisible kind argument (LetZ @{a} a = ...
). A more recent GHC will reject this with:Some
singletons-base
test suite failures that have similar root causes:Singletons/CaseExpressions.hs
:singletons/singletons-base/tests/compile-and-dump/Singletons/CaseExpressions.hs
Lines 25 to 29 in 037fc0e
Singletons/T183.hs
:singletons/singletons-base/tests/compile-and-dump/Singletons/T183.hs
Line 53 in 037fc0e
Singletons/T296.hs
:singletons/singletons-base/tests/compile-and-dump/Singletons/T296.hs
Lines 9 to 13 in 037fc0e
Singletons/T433.hs
:singletons/singletons-base/tests/compile-and-dump/Singletons/T433.hs
Lines 41 to 43 in 037fc0e
Singletons/T581.hs
:singletons/singletons-base/tests/compile-and-dump/Singletons/T581.hs
Lines 30 to 32 in 5f0d420
Truth be told, I'm not quite sure what to do about these sorts of examples. The only way I can imagine fixing this examples is by either rewriting the code or by sprinkling type annotations in random parts of the code. You might think that the takeaway here is "local bindings without top-level type signatures are bad", but that's not quite true, since GHC will continue to accept examples like this one:
Sadly, we may just have to accept that GHC's kind inference just isn't up to the task in all cases and advise users to omit type signatures at their peril.
The text was updated successfully, but these errors were encountered: