Is there a Haskell language extension for the type class method to "use the only potential instance available"?
I want to compile the following
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
class Foo a r where
foo :: a -> r
instance Foo a (Bool -> a) where
foo x _ = x
-- This compiles
-- bar :: Int -> Bool
-- This does not
bar :: a -> Bool
bar _ = True
use :: Bool
use = bar $ foo _5 True
where
_5 :: Int
_5 = 5
Now I get the following error:
No instance for (Foo Int (Bool -> r0))
(maybe you haven't applied enough arguments to a function?)
arising from a use of ‘foo’
The type variable ‘r0’ is ambiguous
Note: there is a potential instance available:
instance Foo a (Bool -> a) -- Defined at tests/pos/Fixme.hs:9:10
But since there is only one potential instance available, is there a way to force ghc to use that instance? Or is there a way to declare some instance as a default instance when types are ambiguous?
The standard trick is to make your instance more polymorphic, thus:
instance (a ~ b, bool ~ Bool) => Foo a (bool -> b) where
foo x _ = x
This precludes you from writing other function instances, but makes it clear what types to use when a function instance is wanted. You will need to turn on the TypeFamilies extension to do this. In your specific case you may be able to get away with just instance a ~ b => Foo a (Bool -> b), which would allow further function instances with other argument types, at the cost of more frequent ambiguity errors.
See a previous answer of mine for some more explanation of this trick.
Related
Why is GHC inferring unification from coercibility of associated data, and why is it contradicting its own checked type signature to do so?
The problem
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
module Lib
(
) where
import Data.Coerce
class Foo a where
data Bar a
data Baz a = Baz
{ foo :: a
, bar :: Bar a
}
type BarSame a b = (Coercible (Bar a) (Bar b), Coercible (Bar b) (Bar a))
withBaz :: forall a b. BarSame a b => (a -> b) -> Baz a -> Baz b
withBaz f Baz{..} = Baz
{ foo = f foo
, bar = coerce bar
}
This is all well and good - GHC will happily compile this code, and is confident that withBaz has the declared signature.
Now, let's try to use it!
instance (Foo a) => Foo (Maybe a) where
data Bar (Maybe a) = MabyeBar (Bar a)
toMaybeBaz :: Baz a -> Baz (Maybe a)
toMaybeBaz = withBaz Just
This gives an error - but a really weird one:
withBaz Just
^^^^^^^^^^^^
cannot construct the infinite type: a ~ Maybe a
Indeed, if I go into GHCi, and ask it to give me the type of withBaz:
ghc>:t withBaz
withBaz :: (b -> b) -> Baz b -> Baz b
That's not the signature I gave it.
Coercibility
I suspect that GHC is treating the type arguments of withBaz as though they have to unify, because it's inferring Coercible a b from Coercible (Bar a) (Bar b). But because it's a data family, they don't even need to be Coercible - certainly not unifiable.
Update!
The following change fixes the compilation:
instance (Foo a) => Foo (Maybe a) where
newtype Bar (Maybe a) = MabyeBar (Bar a)
That is - declare the data family as a newtype, instead of a data. This seems consistent with GHC's treatment of Coercible in the language in general, in that
data Id a = Id a
will not cause a Coercible instance to be generated - even though it should definitely be coercible to a. With the above declaration, this will error:
wrapId :: a -> Id a
wrapId = coerce
But with a newtype declaration:
newtype Id a = Id a
then the Coercible instance exists, and wrapId compiles.
I believe #dfeuer's since-deleted comment about lack of "role" support for type/data families provides the answer.
For a top-level, data-defined parametrized type:
data Foo a = ...
the coercibility of types Foo a and Foo b depends on the role of the parameter a. In particular, if as role is nominal, then Foo a and Foo b are coercible if and only if a and b are precisely the same type.
So, in the program:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RoleAnnotations #-}
import Data.Coerce
type role Foo nominal
data Foo a = Foo
foo :: (Coercible (Foo a) (Foo b)) => a -> b
foo = undefined
because of the nominal role of the parameter a in Foo a, the type of foo is actually simplified to b -> b:
λ> :t foo
foo :: b -> b
If the role annotation is changed from nominal to representational, the type is simplified to Coercible a b => a -> b, and if the role is changed to phantom (the default for this particular declaration of Foo, as a does not appear on the right-hand side), the type is simplified to a -> b. This is all as expected and corresponds to the definition of each of these roles.
Note that if you replaced the declaration of Foo with:
data Foo a = Foo a
then the phantom role would not longer be permitted, but the inferred types for foo under the other two roles would be exactly as before.
However, there's an important difference if you switch from a data to a newtype. With:
newtype Foo a = Foo a
you'd discover that even with type role Foo nominal, the inferred type for foo would be Coercible b a => a -> b instead of b -> b. That's because the algorithm for type-safe coercions handles newtypes differently than "equivalent" data types, as you've noted in your question -- they are always immediately coercible through unwrapping whenever the constructor is in scope, regardless of the role of the type parameter.
So, with all that being said, your experience with associated data families is consistent with the role of the family's type parameter being set to nominal. Though I couldn't find it documented in the GHC manual, this appears to be as-designed behavior, and there's an open ticket that acknowledges all data/type families have all parameters assigned nominal role and proposes relaxing this restriction, and #dfeuer actually has a detailed proposal from this past October.
Why doesn't using an associated type synonym in a signature imply the corresponding constraint?
E.g. why doesn't the following compile:
{-# LANGUAGE TypeApplications, ScopedTypeVariables, TypeFamilies, AllowAmbiguousTypes #-}
class MyClass a where
type AssociatedType a
bar :: Int
foo :: forall a. AssociatedType a -> Int
foo _ = bar #a
ghc 8.6.5 gives the following error:
error:
* No instance for (MyClass a) arising from a use of `bar'
Possible fix:
add (MyClass a) to the context of
the type signature for:
foo :: forall a. AssociatedType a -> Int
* In the expression: bar #a
In an equation for `foo': foo _ = bar #a
|
8 | foo _ = bar #a
| ^^^^^^
GHC documentation doesn't seem to mention this aspect.
If it implied the constraint, then anybody using values of the associated value in any way whatsoever would need to have the constraint in scope. For example,
sort :: Ord a => [a] -> [a]
obviously knows nothing about MyClass, yet it should be possible to use it as sort :: [AssociatedType a] -> [AssociatedType a] provided that you have Ord (AssociatedType a) in the calling scope.
To get behaviour like the one you seem to be looking for, you want a wrapped constraint rather than an associated type. That can't be done with -XTypeFamilies, but it can be done with -XGADTs:
{-# LANGUAGE GADTs #-}
class MyClass a where
bar :: Int
data MyClassWitness a where
MyClassWitness :: MyClass a => MyClassWitness a
foo :: ∀ a. MyClassWitness a -> Int
foo MyClassWitness = bar #a
Instead of a self-rolled wrapper you can also use the one from the constraints library:
import Data.Constraint
foo :: ∀ a . Dict (MyClass a) -> Int
foo Dict = bar #a
Important in both cases is that you actually pattern-match on the GADT constructor, as only that actually brings the constraint into scope. This would not work:
foo :: ∀ a . Dict (MyClass a) -> Int
foo _ = bar #a
Because just using the type does not require the type constraint. For instance, this compiles:
foo :: forall a. AssociatedType a -> Int
foo _ = 42
At runtime, there is no need to pass a typeclass dictionary to this function, which is coherent with the lack of the constraint during type checking.
In your code, the constraint is needed because you are using bar, not because you are using the type.
In the following snippet (I have abstracted all other trivial parts)
data T s = T (s -> s)
foo :: T s -> s -> s
foo (T f) x = bar x where
bar :: s -> s
bar a = f a
I got following error
Couldn't match expected type `s1' with actual type `s'
`s1' is a rigid type variable bound by
the type signature for bar :: s1 -> s1 at /tmp/test.hs:5:12
`s' is a rigid type variable bound by
the type signature for foo :: T s -> s -> s at /tmp/test.hs:3:8
In the return type of a call of `f'
In the expression: f a
In an equation for `bar': bar a = f a
my guess was that the type variables in bar's signature don't share the namespace with foo, so the compiler can't infer that the two s actually mean the same type.
Then I found this page Scoped type variables, which suggests that I can use {-# LANGUAGE ScopedTypeVariables #-}, which didn't help. I got the same error.
Are type variables in “where” clauses in the same namespace with their parents?
No*. This gets a little bit easier if you think of foo :: s -> s in terms of foo :: forall s. s -> s. After all, a type variable indicates that the function works for any type s. Let's add explicit quantifications to your code:
{-# LANGUAGE ExplicitForAll #-}
data T s = T (s -> s)
foo :: forall s. T s -> s -> s
foo (T f) x = bar x where
bar :: forall s. s -> s
bar a = f a
As you can see, there are two forall s. there. But the one in bar is wrong. After all, you cannot choose any s there, but the one already used in s. This can be done by enabling ScopedTypeVariables:
{-# LANGUAGE ScopedTypeVariables #-}
data T s = T (s -> s)
-- vvvvvvvv explicit here
foo :: forall s. T s -> s -> s
foo (T f) x = bar x where
-- vvvvvv same as above here
bar :: s -> s
bar a = f a
However, there are some tricks to get rid of ScopedTypeVariables. For example the following in this case:
data T s = T (s -> s)
foo :: T s -> s -> s
foo (T f) x = (bar `asTypeOf` idType x) x where
bar a = f a
idType :: a -> a -> a
idType a _ = a
-- For completion, definition and type of 'asTypeOf'
-- asTypeOf :: a -> a -> a
-- asTypeOf x _ = x
For any x :: s the term idType x has type s -> s, and asTypeOf enforces both to have the same type.
Depending on your actual code, something like this might be more or less feasible.
* Well, in this case, since it's possible to use ScopedTypeVariables, see later part of the answer.
ScopedTypeVariables are indeed the solution, but there's an extra requirement to use them: You must put explicit foralls in the type signatures declaring the variables you want to scope, like this:
foo :: forall s. T s -> s -> s
This is so that the meaning of signatures in code doesn't depend on whether the extension is enabled or not.
In the example below, I'm trying to make foo return its "expected" polymorphic output type. The idea is that foo returns a polymorphic value and an existential type, and then bar specifies the type of the tuple to be the hidden type. (Of course this only works if the type in bar is also existential, which is true in my case.) The following example compiles:
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
module Foo where
import Data.Proxy
import Data.Typeable
data HiddenType where
Hidden :: (Typeable a) => Proxy a -> HiddenType
foo :: (i,HiddenType)
foo = (undefined, Hidden (Proxy::Proxy Int))
data Foo where
Foo :: i -> Foo
bar :: Foo
bar =
let (x,h) = foo
in case h of
(Hidden (p::Proxy i)) -> Foo (x :: i)
I really need a Typeable constraint on foo:
foo :: (Typeable i) => (i,HiddenType)
When I add that constraint (no other changes), I get these errors:
Foo.hs:20:15:
No instance for (Typeable t0) arising from a use of ‘foo’
The type variable ‘t0’ is ambiguous
Relevant bindings include x :: t0 (bound at Foo.hs:20:8)
Note: there are several potential instances:
instance [overlap ok] Typeable ()
-- Defined in ‘Data.Typeable.Internal’
instance [overlap ok] Typeable Bool
-- Defined in ‘Data.Typeable.Internal’
instance [overlap ok] Typeable Char
-- Defined in ‘Data.Typeable.Internal’
...plus 14 others
In the expression: foo
In a pattern binding: (x, h) = foo
In the expression:
let (x, h) = foo
in case h of { (Hidden (p :: Proxy i)) -> Foo (x :: i) }
Foo.hs:22:35:
Couldn't match expected type ‘a’ with actual type ‘t0’
because type variable ‘a’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor
Hidden :: forall a. Typeable a => Proxy a -> HiddenType,
in a case alternative
at Foo.hs:22:6-24
Relevant bindings include
p :: Proxy a (bound at Foo.hs:22:14)
x :: t0 (bound at Foo.hs:20:8)
In the first argument of ‘Foo’, namely ‘(x :: i)’
In the expression: Foo (x :: i)
Failed, modules loaded: none.
I understand that constraints turn into arguments in core, so it seems to me that the issue here is that GHC can't handle pattern bindings for GADTs. If it could, I could use a recursive let to say something like:
bar :: Foo
bar =
let (x :: i,h) = foo
(Hidden (p::Proxy i)) = h
in Foo x
That should make the constraint in scope, providing the extra argument to foo. My intent here is that h contains some (hidden) concrete type i, which should be used as the concrete type for the polymorphic function
GHC complains:
Foo.hs:19:8:
You cannot bind scoped type variable ‘i’
in a pattern binding signature
In the pattern: x :: i
In the pattern: (x :: i, h)
In a pattern binding:
(x :: i, h) = foo
Foo.hs:20:8:
My brain just exploded
I can't handle pattern bindings for existential or GADT data constructors.
Instead, use a case-expression, or do-notation, to unpack the constructor.
In the pattern: Hidden (p :: Proxy i)
In a pattern binding: (Hidden (p :: Proxy i)) = h
In the expression:
let
(x :: i, h) = foo
(Hidden (p :: Proxy i)) = h
in Foo x
The assumptions for my use case are that
1. foo computes i and the HiddenType simultaneously
2. The value of the hidden type involves (at least partial) computation of the first tuple element. This means I do not want to call foo twice in bar (once to get the HiddenType, and once to use that type to bind the first tuple element).
Is there some way to make the definition of bar possible in the presence of a constraint on foo?
I suppose the problem is that foos return value isn't actually polymorphic. foo itself is polymorphic but the returned value must exist at a specific type. Unfortunately, the type you want to use isn't available yet and cannot be brought into scope at foos call site because of the circular reference. If we write out the definition of foo in pseudo-core, the problem is clear:
foo (# iType) _ = (undefined # iType, HiddenType...)
Here # iType is a type argument. We need to do foo's type application first (and the dictionary application, which is unused) before getting the HiddenType, so there's no way to make this work as-is.
Fortunately, there is a way to convince ghc that foo should return an actual polymorphic value:
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
{-# LANGUAGE ImpredicativeTypes #-}
module Foo where
import Data.Proxy
import Data.Typeable
data HiddenType where
Hidden :: (Typeable a) => Proxy a -> HiddenType
foo :: (forall i. Typeable i => i,HiddenType)
foo = (undefined, Hidden (Proxy::Proxy Int))
data Foo where
Foo :: i -> Foo
bar =
let (x,h) = foo
in case h of
Hidden p -> Foo (x `asProxyTypeOf` p)
If you're familiar with higher-rank types (e.g. the RankNTypes extension), you can think of ImpredicativeTypes as something similar, except for data structures instead of functions. For example, without ImpredicativeTypes you can write:
list1 :: forall t. Typeable t => [t]
which is the type of a list that contains all values of type t, for some t with a Typeable constraint. Even though it's polymorphic, every element of the list will be of the same type! If instead you wish to move the forall inside the list, so that every element may be a different type t, ImpredicativeTypes will allow this:
list2 :: [forall t. Typeable t => t]
It's not a commonly-enabled extension, but it is occasionally useful.
The core for the impredicative version of foo is a bit different as well:
foo = (\(# iType) _ -> undefined # iType, HiddenType...)
You can see that this allows for x to be polymorphic as desired if you add an annotation to the let:
bar :: Foo
bar =
let (x :: forall i. Typeable i => i,h) = foo
in case h of
Hidden p -> Foo (x `asProxyTypeOf` p)
This allows you to delay the instantiation of x at the hidden type until later, when it's available. You still need to box it up inside Foo or another Hidden though, as ghc won't allow the type to escape from under the first Hidden pattern match.
Given the following program:
{-# LANGUAGE DataKinds, GADTs #-}
{-# LANGUAGE TypeFamilies #-}
data Foo = A | B
type family IsA (foo :: Foo) :: Bool
type instance IsA A = True
type instance IsA B = False
data Bar (foo :: Foo) where
BarA :: (IsA foo ~ True) => Int -> Bar foo
BarB :: (IsA foo ~ False) => String -> Bar foo
f :: Bar A -> Int
f bar = case bar of
BarA x -> x
I get this warning from GHC 7.4.2 when using -fwarn-incomplete-patterns for the total function f defined above:
Warning: Pattern match(es) are non-exhaustive
In a case alternative: Patterns not matched: BarB _
Of course, it makes no sense to even try adding a match for BarB:
Couldn't match type `'False' with `'True'
Inaccessible code in
a pattern with constructor
BarB :: forall (foo :: Foo). IsA foo ~ 'False => String -> Bar foo,
in a case alternative
In the pattern: BarB _
In a case alternative: BarB _ -> undefined
In the expression:
case bar of {
BarA x -> x
BarB _ -> undefined }
Is there a way to convince GHC that f is total? Also, is this a bug of GHC, or just a known limitation; or is there actually a very good reason why there's no way to see that the pattern match in f is complete?
It's annoying, yes. GHC has the assumption that type families (and classes) are open baked deeply into its algorithms all over the place; however, you're writing a type family parameterized by a closed kind. This tension explains the misunderstanding between you and GHC. I think there has been some thought about how to handle closed type classes and families, but it's a tricky area.
In the meantime, you can avoid the openness of type families to convince the totality checker.
{-# LANGUAGE DataKinds, GADTs #-}
{-# LANGUAGE TypeFamilies #-}
data Foo = A | B
data Bar (foo :: Foo) where
BarA :: Int -> Bar A -- or BarA :: foo ~ A => Int -> Bar foo
BarB :: String -> Bar B -- or BarB :: foo ~ B => String -> Bar foo
f :: Bar A -> Int
f bar = case bar of
BarA x -> x
-- or f (BarA x) = x
You can always use _ to pattern match to anything as the last condition of the case.
So _ -> undefined instead of BarB _ -> undefined.
This will make case total in its argument.
There is also a library by Neil Mitchell which checks for non exhaustive patterns to prevent runtime failures due to non matching patterns.