GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2019-07-12T12:56:54Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/7395DefaultSignatures conflict with default implementations2019-07-12T12:56:54ZcgaebelDefaultSignatures conflict with default implementationsDefault signatures cannot be used with default implementations.
This is quite annoying for the hashable package, as we'd like to provide both options to the user.
See the attached test case.
<details><summary>Trac metadata</summary>
...Default signatures cannot be used with default implementations.
This is quite annoying for the hashable package, as we'd like to provide both options to the user.
See the attached test case.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------------- |
| Version | 7.6.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | http://hpaste.org/77290 |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"DefaultSignatures conflict with default implementations","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.1","keywords":["DefaultSignatures"],"differentials":[],"test_case":"http://hpaste.org/77290","architecture":"","cc":[""],"type":"Bug","description":"Default signatures cannot be used with default implementations.\r\n\r\nThis is quite annoying for the hashable package, as we'd like to provide both options to the user.\r\n\r\nSee the attached test case.","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/12220TypeApplications and DefaultSignatures - problems deducing type variables.2019-07-07T18:27:06ZmkloczkoTypeApplications and DefaultSignatures - problems deducing type variables.The following example code throws an error.
The example code:
```hs
{-#LANGUAGE TypeApplications#-}
{-#LANGUAGE MultiParamTypeClasses #-}
{-#LANGUAGE AllowAmbiguousTypes #-}
{-#LANGUAGE FlexibleInstances #-}
{-#LANGUAGE ScopedTypeVaria...The following example code throws an error.
The example code:
```hs
{-#LANGUAGE TypeApplications#-}
{-#LANGUAGE MultiParamTypeClasses #-}
{-#LANGUAGE AllowAmbiguousTypes #-}
{-#LANGUAGE FlexibleInstances #-}
{-#LANGUAGE ScopedTypeVariables #-}
{-#LANGUAGE DefaultSignatures #-}
module Test1 where
-- | Type a is only used for
-- type application.
class ToUse a where
toUse :: Int -> Int
-- | The type used for
-- type application
data Default
-- | The instance using Default as type application.
-- To call use:
-- > toUse @Default
instance ToUse Default where
toUse a = 3*a
-- | Typeclass whose methods work
-- only with type application.
class (ToUse a) => Uses a b where
uses :: b -> [b]
-- | Default Signature, which generates the problem.
-- It is the same as the normal one
-- Comment it to 'fix' the bug.
default uses :: b -> [b]
uses v = [v]
-- | Normal instances, nothing special
instance Uses Default Int where
uses v = take (toUse @Default 3) $ repeat v
-- | Another normal one
instance Uses Default String where
uses v = take (toUse @Default 2) $ repeat v
-- | This one works nicely
instance (ToUse t, Uses t a, Uses t b) => Uses t (a,b) where
uses (vl,vr) = zip ls rs
where ls = uses @t vl
rs = uses @t vr
-- | But this one doesn't.
-- Unless you comment the default signature.
instance (ToUse t, Uses t a, Uses t b, Uses t c) => Uses t (a,b,c)
```
The error:
```
• Could not deduce (Uses a0 a)
arising from a use of ‘Test1.$dmuses’
from the context: (ToUse t, Uses t a, Uses t b, Uses t c)
bound by the instance declaration at Test1.hs:47:10-66
The type variable ‘a0’ is ambiguous
Relevant bindings include
uses :: (a, b, c) -> [(a, b, c)] (bound at Test1.hs:47:10)
• In the expression: Test1.$dmuses
In an equation for ‘uses’: uses = Test1.$dmuses
In the instance declaration for ‘Uses t (a, b, c)’
```
Commenting out the default signature fixes the problem.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.0.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"TypeApplications and DefaultSignatures - problems deducing type variables.","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.0.1","keywords":["DefaultSignatures,","TypeApplications"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The following example code throws an error.\r\n\r\nThe example code:\r\n{{{#!hs\r\n{-#LANGUAGE TypeApplications#-}\r\n{-#LANGUAGE MultiParamTypeClasses #-}\r\n{-#LANGUAGE AllowAmbiguousTypes #-}\r\n{-#LANGUAGE FlexibleInstances #-}\r\n{-#LANGUAGE ScopedTypeVariables #-}\r\n{-#LANGUAGE DefaultSignatures #-}\r\nmodule Test1 where\r\n\r\n-- | Type a is only used for\r\n-- type application.\r\nclass ToUse a where\r\n toUse :: Int -> Int\r\n\r\n-- | The type used for\r\n-- type application\r\ndata Default\r\n\r\n\r\n-- | The instance using Default as type application.\r\n-- To call use:\r\n-- > toUse @Default \r\ninstance ToUse Default where\r\n toUse a = 3*a\r\n\r\n-- | Typeclass whose methods work\r\n-- only with type application.\r\nclass (ToUse a) => Uses a b where\r\n uses :: b -> [b]\r\n -- | Default Signature, which generates the problem.\r\n -- It is the same as the normal one\r\n -- Comment it to 'fix' the bug.\r\n default uses :: b -> [b] \r\n uses v = [v] \r\n\r\n-- | Normal instances, nothing special\r\ninstance Uses Default Int where\r\n uses v = take (toUse @Default 3) $ repeat v\r\n-- | Another normal one\r\ninstance Uses Default String where\r\n uses v = take (toUse @Default 2) $ repeat v\r\n\r\n-- | This one works nicely\r\ninstance (ToUse t, Uses t a, Uses t b) => Uses t (a,b) where\r\n uses (vl,vr) = zip ls rs\r\n where ls = uses @t vl\r\n rs = uses @t vr\r\n\r\n-- | But this one doesn't.\r\n-- Unless you comment the default signature.\r\ninstance (ToUse t, Uses t a, Uses t b, Uses t c) => Uses t (a,b,c)\r\n}}}\r\n\r\n\r\nThe error:\r\n{{{\r\n • Could not deduce (Uses a0 a)\r\n arising from a use of ‘Test1.$dmuses’\r\n from the context: (ToUse t, Uses t a, Uses t b, Uses t c)\r\n bound by the instance declaration at Test1.hs:47:10-66\r\n The type variable ‘a0’ is ambiguous\r\n Relevant bindings include\r\n uses :: (a, b, c) -> [(a, b, c)] (bound at Test1.hs:47:10)\r\n • In the expression: Test1.$dmuses\r\n In an equation for ‘uses’: uses = Test1.$dmuses\r\n In the instance declaration for ‘Uses t (a, b, c)’\r\n}}}\r\n\r\nCommenting out the default signature fixes the problem. ","type_of_failure":"OtherFailure","blocking":[]} -->8.0.2https://gitlab.haskell.org/ghc/ghc/-/issues/18432Inferred type variable check is defeated by nested foralls2020-10-31T06:53:59ZRyan ScottInferred type variable check is defeated by nested forallsGHC HEAD will reject the following program:
```hs
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE RankNTypes #-}
module Bug where
class C a where
m :: forall b. forall c. a -> b -> c -> c
default m :: forall {b}. forall c...GHC HEAD will reject the following program:
```hs
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE RankNTypes #-}
module Bug where
class C a where
m :: forall b. forall c. a -> b -> c -> c
default m :: forall {b}. forall c. a -> b -> c -> c
m _ _ = id
```
```
$ ~/Software/ghc5/inplace/bin/ghc-stage2 Bug.hs
[1 of 1] Compiling Bug ( Bug.hs, Bug.o )
Bug.hs:7:3: error:
A default type signature cannot contain inferred type variables
In a class method signature for ‘m’
|
7 | default m :: forall {b}. forall c. a -> b -> c -> c
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
However, a simple change to the default signature will evade this check and cause the program to typecheck successfully:
```hs
default m :: forall b. forall {c}. a -> b -> c -> c
```
This seems inconsistent to me.9.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/17723Using default methods with (r ~ LiftedRep) leads to Iface Lint failure2022-05-07T21:02:22ZRyan ScottUsing default methods with (r ~ LiftedRep) leads to Iface Lint failureI originally spotted this bug when trying to minimize #17722, but I believe this is an entirely different bug.
See also #19519, which makes this bug show up much more often: every use of `liftTyped`.
To reproduce the issue, you'll nee...I originally spotted this bug when trying to minimize #17722, but I believe this is an entirely different bug.
See also #19519, which makes this bug show up much more often: every use of `liftTyped`.
To reproduce the issue, you'll need these two files:
```hs
-- Lib.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
module Lib (C(..)) where
import GHC.Exts
-- Essentially a stripped-down version of the `Lift` type class from
-- Language.Haskell.TH.Syntax. I have redefined it here both to strip away
-- inessential details and to ensure that this test case will not change if
-- the API of Lift were to change in the future.
class C (a :: TYPE (r :: RuntimeRep)) where
m :: a -> ()
default m :: (r ~ LiftedRep) => a -> ()
m = const ()
```
```hs
-- Bug.hs
module Bug where
import Lib
data Foo
instance C Foo
```
Next, compile them with a recent version of GHC like so:
```
$ /opt/ghc/8.8.2/bin/ghc -c Lib.hs -O -dcore-lint && /opt/ghc/8.8.2/bin/ghc -c Bug.hs -O -dcore-lint
ghc: panic! (the 'impossible' happened)
(GHC version 8.8.2 for x86_64-unknown-linux):
Iface Lint failure
In interface for Lib
Unfolding of $dmm
<no location info>: warning:
In the type ‘(a_a1a9 |> Sym (TYPE (Sym co_a1ac))_N) -> ()’
co_a1ac :: r_a1a8 ~# 'LiftedRep
[LclId[CoVarId]] is out of scope
$dmm = \ (@ (r_a1a8 :: RuntimeRep))
(@ (a_a1a9 :: TYPE r_a1a8))
($dC_a1aa :: C a_a1a9)
($d~_a1ab :: r_a1a8 ~ 'LiftedRep) ->
case eq_sel @ RuntimeRep @ r_a1a8 @ 'LiftedRep $d~_a1ab of co_a1ac
{ __DEFAULT ->
\ (ds_a1ad :: (a_a1a9 |> Sym (TYPE (Sym co_a1ac))_N)) -> ()
}
Iface expr = \ @ r :: RuntimeRep
@ a :: TYPE r
($dC :: C a)
($d~ :: r ~ 'LiftedRep) ->
case eq_sel @ RuntimeRep @ r @ 'LiftedRep $d~ of co { DEFAULT ->
\ (ds :: (a |> Sym (TYPE (Sym co))_N)) -> () }
Call stack:
CallStack (from HasCallStack):
callStackDoc, called at compiler/utils/Outputable.hs:1159:37 in ghc:Outputable
pprPanic, called at compiler/iface/TcIface.hs:1546:33 in ghc:TcIface
Please report this as a GHC bug: https://www.haskell.org/ghc/reportabug
```
I have observed this panic on every version of GHC from 8.2.2 to HEAD.
Another strange thing about this program is that I have to write `m = const ()`. If I instead try to define it like `m _ = ()`, I get the following error:
```
$ /opt/ghc/8.8.2/bin/ghc -c Lib.hs -O -dcore-lint && /opt/ghc/8.8.2/bin/ghc -c Bug.hs -O -dcore-lint
Lib.hs:19:5: error:
A levity-polymorphic type is not allowed here:
Type: a
Kind: TYPE r
In a wildcard pattern
|
19 | m _ = ()
| ^
```
This seems suspicious, does it not? Why should that binder get rejected for being levity polymorphic if `r ~ LiftedRep`? Shouldn't that make the binder levity monomorphic?9.2.2https://gitlab.haskell.org/ghc/ghc/-/issues/23884Unexpected representation-polymorphism error when using default signatures2024-01-11T21:24:47Zsheafsam.derbyshire@gmail.comUnexpected representation-polymorphism error when using default signaturesI would expect the following program from @adamgundry to work, but it doesn't:
```haskell
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FunctionalDependencies #-}
module T23884 where
import Data....I would expect the following program from @adamgundry to work, but it doesn't:
```haskell
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FunctionalDependencies #-}
module T23884 where
import Data.Kind
import GHC.Exts
type SetField :: forall {k} {r_rep} {a_rep} . k -> TYPE r_rep -> TYPE a_rep -> Constraint
class SetField x r a | x r -> a where
modifyField :: (a -> a) -> r -> r
setField :: a -> r -> r
default setField :: (a_rep ~ LiftedRep) => a -> r -> r
setField x = modifyField (\ _ -> x)
```
```
T23884.hs:16:3: error: [GHC-55287]
The first pattern in the equation for `setField'
does not have a fixed runtime representation.
Its type is:
a :: TYPE a_rep
|
16 | setField x = modifyField (\ _ -> x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
T23884.hs:16:36: error: [GHC-55287]
* The binder of the lambda expression
does not have a fixed runtime representation.
Its type is:
a0 :: TYPE a_rep0
Cannot unify `a_rep' with the type variable `a_rep0'
because the former is not a concrete `RuntimeRep'.
* In the expression: x
In the first argument of `modifyField', namely `(\ _ -> x)'
In the expression: modifyField (\ _ -> x)
```https://gitlab.haskell.org/ghc/ghc/-/issues/19432GHC 9.0 rejects default signature that 8.10 accepts2021-03-03T18:29:53ZRyan ScottGHC 9.0 rejects default signature that 8.10 acceptsI originally noticed this issue in the `barbies-2.0.2.0` library on Hackage, which compiles with GHC 8.10.4 but fails to compile on GHC 9.0.1. Here is a minimized version of the code that fails to compile on 9.0.1:
```hs
{-# LANGUAGE Co...I originally noticed this issue in the `barbies-2.0.2.0` library on Hackage, which compiles with GHC 8.10.4 but fails to compile on GHC 9.0.1. Here is a minimized version of the code that fails to compile on 9.0.1:
```hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Bug where
import Data.Coerce
import Data.Kind
import Data.Proxy
import GHC.Generics
import GHC.TypeNats
class FunctorT (t :: (k -> Type) -> k' -> Type) where
tmap :: forall f g
. (forall a . f a -> g a)
-> (forall x . t f x -> t g x)
-- Default implementation of 'tmap' based on 'Generic'.
default tmap
:: forall f g
. (forall a . f a -> g a)
-> (forall x. CanDeriveFunctorT t f g x => t f x -> t g x)
tmap f = toP (Proxy @1) . gmap (Proxy @1) f . fromP (Proxy @1)
type CanDeriveFunctorT t f g x
= ( GenericP 1 (t f x)
, GenericP 1 (t g x)
, GFunctor 1 f g (RepP 1 (t f x)) (RepP 1 (t g x))
)
-----
class GFunctor (n :: Nat) f g repbf repbg where
gmap :: Proxy n -> (forall a . f a -> g a) -> repbf x -> repbg x
class
( Coercible (Rep a) (RepP n a)
, Generic a
) => GenericP (n :: Nat) (a :: Type) where
type family RepP n a :: Type -> Type
toP :: Proxy n -> RepP n a x -> a
fromP :: Proxy n -> a -> RepP n a x
```
The important bit is the default signature for `tmap`. With GHC 9.0.1, this is rejected thusly:
```
$ /opt/ghc/9.0.1/bin/ghc Bug.hs
[1 of 1] Compiling Bug ( Bug.hs, Bug.o )
Bug.hs:24:11: error:
• The default type signature for tmap:
forall (f :: k -> *) (g :: k -> *).
(forall (a :: k). f a -> g a)
-> forall (x :: k'). CanDeriveFunctorT t f g x => t f x -> t g x
does not match its corresponding non-default type signature
• When checking the class method:
tmap :: forall k k' (t :: (k -> *) -> k' -> *) (f :: k -> *)
(g :: k -> *).
FunctorT t =>
(forall (a :: k). f a -> g a) -> forall (x :: k'). t f x -> t g x
In the class declaration for ‘FunctorT’
|
24 | default tmap
| ^^^^
```
Why does GHC 9.0.1 reject this? According to the [GHC User's Guide section on `DefaultSignatures`](https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/default_signatures.html#default-method-signatures):
> The type signature for a default method of a type class must take on the same form as the corresponding main method’s type signature. Otherwise, the typechecker will reject that class’s definition. By “take on the same form”, we mean that the default type signature should differ from the main type signature only in their contexts.
As far as I can tell, `tmap` meets this criterion, as the only difference between the two signatures is the presence of `CanDeriveFunctorT t f g x =>` in the default signature.https://gitlab.haskell.org/ghc/ghc/-/issues/18259False-positive redundant-constraint warning on constrained default instance m...2020-07-14T14:19:18Zinfinity0False-positive redundant-constraint warning on constrained default instance methodTested on GHC 8.10.1:
```haskell
{-# LANGUAGE DefaultSignatures #-}
{-# OPTIONS_GHC -Werror -Wredundant-constraints #-}
class Base a where
myList :: [a]
default myList :: SubClass a => [a]
myList = defaultMyList
class Base a =>...Tested on GHC 8.10.1:
```haskell
{-# LANGUAGE DefaultSignatures #-}
{-# OPTIONS_GHC -Werror -Wredundant-constraints #-}
class Base a where
myList :: [a]
default myList :: SubClass a => [a]
myList = defaultMyList
class Base a => SubClass a where
myList2 :: [a]
defaultMyList :: SubClass a => [a]
defaultMyList = myList2
main :: IO ()
main = pure ()
```
The error is as follows:
~~~~
Test.hs:7:11: error: [-Wredundant-constraints, -Werror=redundant-constraints]
• Redundant constraint: Base a
• In the type signature for:
myList :: forall a. (Base a, SubClass a) => [a]
In the ambiguity check for ‘myList’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method: myList :: forall a. Base a => [a]
|
7 | default myList :: SubClass a => [a]
| ^^^^^^
~~~~
suggesting that some automatic process is adding `(Base a)` as an implicit constraint, but then this redundancy check is failing on the automatically-added constraint - which it shouldn't because the programmer can't do anything about it.
Adding `AllowAmbiguousTypes` does make the error go away, as the error message suggests, however the type is not ambiguous - there is no false-positive for `defaultMyList` with the same (source-level) signature. Adding `ConstrainedClassMethods` makes no difference.https://gitlab.haskell.org/ghc/ghc/-/issues/17711Default method (/ type family) can't be given at a more specific kind2020-01-20T02:31:51ZIcelandjackDefault method (/ type family) can't be given at a more specific kind## Motivation
Haskell is very stubborn about kinds :) if I have the following type class
```haskell
{-# Language DataKinds #-}
{-# Language KindSignatures #-}
{-# Language PolyKinds #-}
{-# Language TypeFamilies #-}
import...## Motivation
Haskell is very stubborn about kinds :) if I have the following type class
```haskell
{-# Language DataKinds #-}
{-# Language KindSignatures #-}
{-# Language PolyKinds #-}
{-# Language TypeFamilies #-}
import Prelude hiding (Functor (..))
import qualified Prelude
import Data.Kind
import Data.Type.Equality
type Cat ob = (ob -> ob -> Type)
class Functor (f :: src -> tgt) where
type Source f :: Cat src
type Target f :: Cat tgt
fmap :: Source f a a' -> Target f (f a) (f a')
```
I might want to do two things that GHC doesn't let me do, this issue is about the latter
* Default `Source f` and `Target f` to be `(->)`
* Default `fmap = Prelude.fmap` when `f::Type->Type`, `Source f` = `Target f` = `(->)`.. and there is a `Prelude.Functor f` instance.
The first is quite easily remedied by defining `Source f` = `Target f` = `(-->)`
```haskell
type (-->)
type family (-->) :: Cat ob
type instance (-->) @Type = (->)
```
But the second one is more complicated.
## Proposal
I think this should work:
```haskell
default fmap :: (Prelude.Functor f, Source f ~ (->), Target f ~ (->)) => Source f a a' -> Target f (f a) (f a')
fmap = Prelude.fmap
```
If GHC detects that the class variable is used at a different kind then it should only instantiate the default definition at that kind. It's understandable that `f::s->t` can't be used as `::Type->Type` but since it's for defaulting I think it's not problematic
```haskell
-- • Expected kind ‘* -> *’, but ‘f’ has kind ‘src -> tgt’
-- • In the first argument of ‘Functor’, namely ‘f’
-- In the type signature:
-- fmap :: (Functor f, Source f ~ (->), Target f ~ (->)) =>
-- Source f a a' -> Target f (f a) (f a')
```
We can even index default methods on their kind
## Workaround
This is my workaround to package all the necessary facts to use `Prelude.fmap` as default
* Default `fmap = Prelude.fmap` when `f::Type->Type`, `Source f` = `Target f` = `(->)`.. and there is a `Prelude.Functor f` instance.
```haskell
type OldFunctor :: (src -> tgt) -> Type
data OldFunctor f where
OldFunctor :: (Prelude.Functor f, Source f ~ (->), Target f ~ (->)) => OldFunctor @Type @Type f
type OldFunctorC :: (src -> tgt) -> Constraint
class OldFunctorC (f :: src -> tgt) where
oldfunctor :: OldFunctor @src @tgt f
instance (f ~~ f', Prelude.Functor f', src ~ Type, tgt ~ Type, Target f' ~ (->), Source f' ~ (->)) => OldFunctorC (f :: src -> tgt) where
oldfunctor :: OldFunctor @Type @Type f
oldfunctor = OldFunctor
class .. where
fmap :: Source f a a' -> Target f (f a) (f a')
default fmap :: OldFunctorC f => Source f a a' -> Target f (f a) (f a')
fmap | OldFunctor <- oldfunctor @src @tgt @f = Prelude.fmap
```https://gitlab.haskell.org/ghc/ghc/-/issues/17224Backpack and instance defaults2020-10-18T02:01:41ZJohn EricsonBackpack and instance defaults[N.B. #17190 may be useful for some backstory.]
In Haskell today, if an associated type or data family has a default instance, hsig and hs-boot interfaces unconditionally opt-into that default. Unlike regular methods, the definition i...[N.B. #17190 may be useful for some backstory.]
In Haskell today, if an associated type or data family has a default instance, hsig and hs-boot interfaces unconditionally opt-into that default. Unlike regular methods, the definition is meaningful for an abstract instance because we use it at the type level. And yes, that means with dependent Haskell we will have this problem regular methods too, when everything can be reasoned about equationally (#13149).
Also, in the short term interfaces don't support type families so this is extra bad because it means one cannot use defaults with interfaces at all, not just when they intend to declare an instance that doesn't necessary opt into the default. (symptom with defaults #17190, underlying issue with type families #8441).
Given all that, I think we should choose a syntax for opting in or out of defaults in signatures. I furthermore think we should choose it real soon because #8441 is said by @ezyang to be had to implement, and I'd like to resolve #17190 in both a forwards-compatible fashion without crossing that minefield.
I see two choices:
1. `default foo, Foo` syntax to indicate a method (Type or term level) opts into a default.
2. Deprecate default methods. It keeps on requiring new syntax (default sigs, this) and isn't as flexible as deriving-via. Fix any outstanding issues with deriving-via and default methods.https://gitlab.haskell.org/ghc/ghc/-/issues/17212Allow default methods to be implemented using template haskell2023-06-12T14:48:02ZMatthew PickeringAllow default methods to be implemented using template haskellIn conversations with @kosmikus he suggested that it would be nice to integrate default implementations with typed template haskell.
For example,
```
class Eq a where
eq :: a -> a -> Bool
default splice eq :: Generic a => Cod...In conversations with @kosmikus he suggested that it would be nice to integrate default implementations with typed template haskell.
For example,
```
class Eq a where
eq :: a -> a -> Bool
default splice eq :: Generic a => Code (a -> a -> Bool)
eq = _impl_
```
This has the massive advantage that the default implementation can be efficient than the usual `Data` or `Generics` based implementations.
There would need to be a GHC proposal related to this ticket but I write it down here in case anyone else finds it interesting.
Related to #12457Matthew PickeringMatthew Pickeringhttps://gitlab.haskell.org/ghc/ghc/-/issues/15120Default methods don't pass implicit kind parameters properly2019-07-07T18:14:11ZmbieleckDefault methods don't pass implicit kind parameters properlyWhen compiling the following module:
```hs
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DefaultSignatures #-}
module TestCase where
import Data.Proxy
class Describe a where
describe :: Proxy a -> String
default describe :: Proxy a -> ...When compiling the following module:
```hs
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DefaultSignatures #-}
module TestCase where
import Data.Proxy
class Describe a where
describe :: Proxy a -> String
default describe :: Proxy a -> String
describe _ = ""
data Foo = Foo
instance Describe Foo
```
I get the following error (on GHC 8.0.2 and 8.2.2, with `-fprint-explicit-kinds`):
```
TestCase.hs:15:10: error:
• Couldn't match type ‘*’ with ‘Foo’
Expected type: Proxy * Foo -> String
Actual type: Proxy Foo Foo -> String
• In the expression: TestCase.$dmdescribe @Foo
In an equation for ‘describe’: describe = TestCase.$dmdescribe @Foo
In the instance declaration for ‘Describe * Foo’
|
15 | instance Describe Foo
| ^^^^^^^^^^^^
```
The Core generated for `$dmdescribe` has the following type signature:
```
TestCase.$dmdescribe
:: forall k (a :: k). Describe k a => Proxy k a -> String
```
I believe the failure results from the fact that the type application `TestCase.$dmdescribe @Foo` passes `Foo` as the `k` parameter instead of `a`.
Seems related to #13998 .
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.2.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Default methods don't pass implicit kind parameters properly","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.2.2","keywords":["DefaultSignatures","PolyKinds,"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"When compiling the following module:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE PolyKinds #-}\r\n{-# LANGUAGE DefaultSignatures #-}\r\nmodule TestCase where\r\n\r\nimport Data.Proxy\r\n\r\nclass Describe a where\r\n describe :: Proxy a -> String\r\n\r\n default describe :: Proxy a -> String\r\n describe _ = \"\"\r\n\r\ndata Foo = Foo\r\n\r\ninstance Describe Foo\r\n}}}\r\n\r\nI get the following error (on GHC 8.0.2 and 8.2.2, with `-fprint-explicit-kinds`):\r\n\r\n{{{\r\nTestCase.hs:15:10: error:\r\n • Couldn't match type ‘*’ with ‘Foo’\r\n Expected type: Proxy * Foo -> String\r\n Actual type: Proxy Foo Foo -> String\r\n • In the expression: TestCase.$dmdescribe @Foo\r\n In an equation for ‘describe’: describe = TestCase.$dmdescribe @Foo\r\n In the instance declaration for ‘Describe * Foo’\r\n |\r\n15 | instance Describe Foo\r\n | ^^^^^^^^^^^^\r\n}}}\r\n\r\nThe Core generated for `$dmdescribe` has the following type signature:\r\n\r\n{{{\r\nTestCase.$dmdescribe\r\n :: forall k (a :: k). Describe k a => Proxy k a -> String\r\n}}}\r\n\r\nI believe the failure results from the fact that the type application `TestCase.$dmdescribe @Foo` passes `Foo` as the `k` parameter instead of `a`.\r\n\r\nSeems related to https://ghc.haskell.org/trac/ghc/ticket/13998 .","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/10087DefaultSignatures: error message mentions internal name2020-02-11T12:47:33Zandreas.abelDefaultSignatures: error message mentions internal name```hs
{-# LANGUAGE DefaultSignatures #-}
class C a where
reflexive :: a -> Bool
default reflexive :: Eq a => a -> Bool
reflexive x = x == x
data D
instance C D where
-- /home/abel/play/haskell/bugs/DefaultSig.hs:10:10:
-- N...```hs
{-# LANGUAGE DefaultSignatures #-}
class C a where
reflexive :: a -> Bool
default reflexive :: Eq a => a -> Bool
reflexive x = x == x
data D
instance C D where
-- /home/abel/play/haskell/bugs/DefaultSig.hs:10:10:
-- No instance for (Eq D) arising from a use of ‘Main.$gdmreflexive’
-- In the expression: Main.$gdmreflexive
-- In an equation for ‘reflexive’: reflexive = Main.$gdmreflexive
-- In the instance declaration for ‘C D’
```
Error looks odd: The user has not written $gdmreflexive in his code.
TODO: Better error message.
Maybe this should just trigger a warning that method `reflexive` is undefined for instance `D` of `C`. Like when I remove the default method.
```
/home/abel/play/haskell/bugs/DefaultSig.hs:10:10: Warning:
No explicit implementation for
‘reflexive’
In the instance declaration for ‘C D’
```
It seems the semantics of a default signature is that each instance \*must\* implement this method.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------------- |
| Version | 7.8.4 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (Type checker) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"DefaultSignatures: error message mentions internal name","status":"New","operating_system":"","component":"Compiler (Type checker)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.4","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"{{{#!hs\r\n{-# LANGUAGE DefaultSignatures #-}\r\n\r\nclass C a where\r\n reflexive :: a -> Bool\r\n default reflexive :: Eq a => a -> Bool\r\n reflexive x = x == x\r\n\r\ndata D\r\n\r\ninstance C D where\r\n\r\n-- /home/abel/play/haskell/bugs/DefaultSig.hs:10:10:\r\n-- No instance for (Eq D) arising from a use of ‘Main.$gdmreflexive’\r\n-- In the expression: Main.$gdmreflexive\r\n-- In an equation for ‘reflexive’: reflexive = Main.$gdmreflexive\r\n-- In the instance declaration for ‘C D’\r\n}}}\r\n\r\nError looks odd: The user has not written $gdmreflexive in his code.\r\n\r\nTODO: Better error message.\r\n\r\nMaybe this should just trigger a warning that method {{{reflexive}}} is undefined for instance {{{D}}} of {{{C}}}. Like when I remove the default method. \r\n\r\n{{{\r\n/home/abel/play/haskell/bugs/DefaultSig.hs:10:10: Warning:\r\n No explicit implementation for\r\n ‘reflexive’\r\n In the instance declaration for ‘C D’\r\n}}}\r\n\r\nIt seems the semantics of a default signature is that each instance *must* implement this method.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/8067-XDefaultSignatures panic in type error diagnostic2019-07-07T18:46:37ZexFalso-XDefaultSignatures panic in type error diagnosticThe following piece of code shouldn't (and doesn't) typecheck, however GHC panics during the diagnostic.
```
$ cat /tmp/Weird.hs
{-# LANGUAGE DefaultSignatures #-}
module Weird where
import Control.Monad.Trans
class Class a where
...The following piece of code shouldn't (and doesn't) typecheck, however GHC panics during the diagnostic.
```
$ cat /tmp/Weird.hs
{-# LANGUAGE DefaultSignatures #-}
module Weird where
import Control.Monad.Trans
class Class a where
fun :: () -> () -> a
default fun :: () -> () -> m a
fun = lift
$ ghc /tmp/Weird.hs
[1 of 1] Compiling Weird ( /tmp/Weird.hs, /tmp/Weird.o )
/tmp/Weird.hs:9:11:
Couldn't match kind `* -> *' with `*'
Expected type: ()ghc: panic! (the 'impossible' happened)
(GHC version 7.6.3 for x86_64-unknown-linux):
kindFunResult ghc-prim:GHC.Prim.*{(w) tc 34d}
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"-XDefaultSignatures panic in type error diagnostic","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":["defaultsignatures","panic"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The following piece of code shouldn't (and doesn't) typecheck, however GHC panics during the diagnostic.\r\n\r\n{{{\r\n$ cat /tmp/Weird.hs\r\n{-# LANGUAGE DefaultSignatures #-}\r\nmodule Weird where\r\n\r\nimport Control.Monad.Trans\r\n\r\nclass Class a where\r\n fun :: () -> () -> a\r\n default fun :: () -> () -> m a\r\n fun = lift\r\n\r\n$ ghc /tmp/Weird.hs\r\n[1 of 1] Compiling Weird ( /tmp/Weird.hs, /tmp/Weird.o )\r\n\r\n/tmp/Weird.hs:9:11:\r\n Couldn't match kind `* -> *' with `*'\r\n Expected type: ()ghc: panic! (the 'impossible' happened)\r\n (GHC version 7.6.3 for x86_64-unknown-linux):\r\n\tkindFunResult ghc-prim:GHC.Prim.*{(w) tc 34d}\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->