Haskell: interaction between ConstraintKinds, and TypeSynonymInstances - haskell

I'm getting an unexpected error when trying to compile a small Haskell file with GHC 8.6.1 when using ConstraintKinds and TypeSynonymInstances.
I'd like to make a class that takes a class as a parameter, and I'd like to use an alias when writing an instance. Here's the code:
{-# LANGUAGE ConstraintKinds, KindSignatures, TypeSynonymInstances #-}
module TypeAlias where
import Data.Kind
class Foo a
class Bar a
class Baz (c :: * -> Constraint)
instance Baz Foo -- compiles
instance Baz Bar -- compiles
type FooBar a = (Foo a, Bar a) -- compiles
instance Baz FooBar -- fails!
-- TypeAlias.hs:17:10-19: error:
-- • The type synonym ‘FooBar’ should have 1 argument, but has been given none
-- • In the instance declaration for ‘Baz FooBar’
-- |
-- 17 | instance Baz FooBar
-- | ^^^^^^^^^^
The error is surprising because, as far as I can tell, FooBar has the expected kind, namely * -> Constraint, but the compiler says it should be fed an argument.
Is it even possible to use a constraint alias in an instance declaration as I am trying here? If so, how do I make sense of the seemingly contradictory error message?
(I know I can simply declare FooBar as a class instead of an alias, but I really don't want to because I'd also want an instance and at that point I'd have to pull in UndecidableInstances.)

Turns out, Ed Kmett answered my question a year ago. I can't do it with type aliases, but using UndecidableInstances should be benign for this particular situation:
https://www.reddit.com/r/haskell/comments/5zjwym/when_is_undecidableinstances_okay_to_use/
Here's how Kmett might suggest fixing the above example:
{-# LANGUAGE ConstraintKinds, FlexibleInstances,
KindSignatures, UndecidableInstances #-}
module NotTypeAlias where
import Data.Kind
class Foo a
class Bar a
class Baz (c :: * -> Constraint)
instance Baz Foo -- compiles
instance Baz Bar -- compiles
class (Foo a, Bar a) => FooBar a
instance (Foo a, Bar a) => FooBar a -- compiles
instance Baz FooBar -- compiles
Kmett argues that if the instance of FooBar we provide is the sole instance ever in scope, then the type checker won't fall into an infinite loop from our use of UndecidableInstances. I'm satisfied to take him at his word.

Related

Haskell - GADTs pattern match with class constraints

Consider the following example
{-# LANGUAGE DataKinds, GADTs #-}
data Phantom = A | B
data Foo (a :: Phantom) where
FooA :: Foo 'A
FooB :: Foo 'B
class PhantomConstraint (a :: Phantom)
instance PhantomConstraint 'A -- Note: No instance for 'B
someFunc :: PhantomConstraint a => Foo a -> ()
someFunc FooA = ()
If I do something like this GHC complains that the pattern matches are inexhaustive for someFunc, however, if I do try and include the case for FooB (which I don't want to do for domain specific reasons) it complains that it can't deduce the instance of PhantomConstraint for Foo 'B
Is there any way to make GADT pattern matching aware of typeclass constraints such that it eliminates required arms of pattern matching?
EDIT: More details around what I want to do. I have a bucket of types that are all somewhat related but have different properties. In the OO world this is what people use subtyping and inheritance for. However in the FP community, the consensus seems to be that there is no real good way to do subtyping, so in this case I need to hack around it. As such I have a GADT that unifies all of the types, but with different parameters on that type. I then proceed to write different typeclasses and typeclass instances on the type parameters (enabled by datakinds, no term representation). I want to be able to express that some of these types from the datakinds have a property that others don't, but they all do share certain common properties so I don't really want to break up the type. The only other option I can foresee is to create a taxonomy on the type part, but then the DataKinds types get messed up.
I can't reproduce the issue. This loads without warnings or errors in GHCi 8.4.3.
{-# LANGUAGE GADTs, DataKinds, KindSignatures #-}
{-# OPTIONS -Wall #-}
module GADTwarning2 where
data Phantom = A | B
data Foo (a :: Phantom) where
FooA :: Foo 'A
FooB :: Foo 'B
class PhantomConstraint (a :: Phantom)
instance PhantomConstraint 'A -- Note: No instance for 'B
someFunc :: PhantomConstraint a => Foo a -> ()
someFunc FooA = ()
someFunc FooB = ()
As luqui explained in a comment, we can't avoid the FooB case, since type classes are open, and another instance could be added later on by another module, making the pattern match non exhaustive.
If you are absolutely sure you don't need any other instances except the one for A, you can try to use
class a ~ 'A => PhantomConstraint (a :: Phantom)
Or, if the index a can be 'A or 'B, but never a third constructor 'C, then we can try to reify this fact:
class PhantomConstraint (a :: Phantom) where
aIsAOrB :: Either (a :~: 'A) (a :~: 'B)
and then exploit this member later on.

Why can I not use type variables in this instance declaration?

I'm trying to use TypeApplications to disambiguate between which instance of a type class I am calling. Unfortunately, it seems that an instance declaration's type parameters cannot be used in the instance body. Specifically, in this toy example:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
class Foo a where
foo :: String
instance Foo () where
foo = "()"
instance Foo Int where
foo = "Int"
class Bar b where
bar :: String
instance Foo a => Bar a where
bar = foo #a
will error with Not in scope: type variable 'a' at the last line. If I remove the type application, instead the error Could not deduce (Foo a0) from the context Foo a is given, which is reasonable, ass foo by itself is ambiguous.
Is there some way for me to access the type parameter, or otherwise coerce the compiler into recognising this?
A type variable can be used in an instance declaration, but only if it's scoped:
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE TypeApplications, AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables, UnicodeSyntax #-}
class Foo a where foo :: String
class Bar b where bar :: String
instance ∀ a . Foo a => Bar a where
bar = foo #a
As always, ∀ can also be written forall if you prefer ASCII.

Why is this type variable ambiguous, although it should be in scope?

Consider the following code:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
class Foo a where
type Bar a
class Foo a => Foo2 a where
bar :: Bar a
It gives the following error message in GHC 8.2:
error:
• Couldn't match expected type ‘Bar a’ with actual type ‘Bar a0’
NB: ‘Bar’ is a type function, and may not be injective
The type variable ‘a0’ is ambiguous
• In the ambiguity check for ‘bar’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method: bar :: forall a. Foo2 a => Bar a
In the class declaration for ‘Foo2’
|
7 | bar :: Bar a
| ^^^^^^^^^^^^
What's the problem? Why does it universally quantify over a? If I change the last line to
bar :: a
the problem vanishes. Why doesn't it have the type variable a in scope otherwise?
(I looked through all "ambiguous type variable" questions now, but nothing seems to help.)
Imagine you make two Foo instances with the same associated type, and then defined
..
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeApplications #-}
..
instance Foo Int where type Bar Int = Bool
instance Foo Float where type Bar Float = Bool
instance Foo2 Int where
bar :: Bool
bar = False
instance Foo2 Float where
bar :: Bool
bar = True
This means that the type of bar is not enough to decide between the Foo2 Int and Foo2 Float instances.
bar :: Foo2 a => Bar a
GHC will attempt to infer the type a for you but if you ask for
bar :: Bool
it has no way to pick between Int / Float or any other instance that may come later. You must explicitly specify the type with -XTypeApplications
>>> :set -XTypeApplications
>>
>> bar #Int
False
>> bar #Float
True
Edit: If every instance of Foo is a different type (Foo is injective) you can specify that the result determines the instance type with this syntax .. = res | res -> a
..
{-# Language TypeFamilyDependencies #-}
class Foo a where
type Bar a = res | res -> a
You can't define Bar Int and Bar Float both equal to Bool. If we only define Foo Int and Foo2 Int then bar :: Bool is enough to let GHC know you're looking for bar #Int = False.

How to make this example of pseudo-ducktyping type unambiguously without annotations

I wanted to demonstrate the idea of statically verifiable duck typing in Haskell using MultiParamTypeClasses, but I am having trouble avoiding type ambiguity.
Here is the code:
{-# LANGUAGE MultiParamTypeClasses #-}
class HasBar a b where
bar :: b -> a
data Foo = Foo { barBool :: Bool } deriving (Show)
instance HasBar Bool Foo where
bar = barBool
data Bazz = Bazz { barInt :: Int } deriving (Show)
instance HasBar Int Bazz where
bar = barInt
When I load it into GHCi and try to do bar (Foo True) or bar (Bazz 5) I get a Non type-variable argument error and it suggests FlexibleContexts, which just changes the error to an ambiguity error. Now doing something like False || bar (Foo True) works fine. But that doesn't seem like it should be needed as Foo is only a member of the typeclass that returns a Bool.
It seems like the issue is something to do with the possibility of something like:
instance HasBar Int Foo where
bar = const 5
Which would necessitate the types being ambiguous. But if there is just one instance I don't see why there are any issues preventing Haskell from finding out the type (do I need some sort of extension). If I can't do it that way then is there an alternative to MultiParamTypeClasses that only allows one instance and would allow for this pseudo-ducktyping type of thing to work?
the problem is that it's not only looking for what it sees but what it can know - and there is the possibility for you to make an instance that will be HasBar Int Foo as well so it complains
You can get rid of this with either FunctionalDependencies or TypeFamilies
using functional dependencies
the first extension is probably the way to go here (you don't have to change much of your code). You can basically tell GHCi, that the type b in your class/constraint will be enough to decide the type a.
if you change it to:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
class HasBar a b | b -> a where
bar :: b -> a
it'll work (you need the FlexibleContexts only in GHCi
λ> :set -XFlexibleContexts
λ> bar (Foo True)
True
using type families
In case you are interested here is the same thing with type-families and associated types:
{-# LANGUAGE TypeFamilies #-}
class HasBar a where
type Bar a :: *
bar :: a -> Bar a
data Foo = Foo { barBool :: Bool } deriving (Show)
instance HasBar Foo where
type Bar Foo = Bool
bar = barBool
data Bazz = Bazz { barInt :: Int } deriving (Show)
instance HasBar Bazz where
type Bar Bazz = Int
bar = barInt
note that you don't need the MultiParamTypeClasses any more

Promoting complex GADTs

I've been toying around with -XDataKinds recently, and was wondering why Foo below won't be automatically promoted:
{-# LANGUAGE
GADTs
, DataKinds
, KindSignatures #-}
import Data.HList
data Foo a where
Foo :: Bar a =>
a -> Foo a
data Baz where
Baz :: (a ~ HList (l :: [Foo *])) =>
a -> Baz
That is, Baz is a heterogenous list of Foo a's, where a is constrained by Bar.
Is there a way to manually create a promoted version of this data type? How would I go about doing so? Can kinds be declared? Could I make a dummy Haskell98 version of Foo, and separate it into a module or something? Ideally I'd like to keep the constraint context, but I don't think there's a Constraint sort. Any ideas would be very helpful!

Resources