Liberal coverage condition introduced in GHC 7.7 breaks code valid in GHC 7.6 - haskell

The idea
I'm writing a DSL, which compiles to Haskell.
Users of this language can define own immutable data structures and associated functions. By associated function I mean a function, which belongs to a data structure.
For example, user can write (in "pythonic" pseudocode):
data Vector a:
x,y,z :: a
def method1(self, x):
return x
(which is equivalent to the following code, but shows also, that associated functions beheva like type classes with open world assumption):
data Vector a:
x,y,z :: a
def Vector.method1(self, x):
return x
In this example, method1 is a function associated with Vector data type, and can be used like v.testid(5) (where v is instance of Vector data type).
I'm translating such code to Haskell code, but I'm facing a problem, which I'm trying to solve for a long time.
The problem
I'm trying to move the code from GHC 7.6 over GHC 7.7 (which is pre-release of 7.8) (Newer versions can be compiled from sources). The code works perfectly under GHC 7.6, but does not under GHC 7.7.
I want to ask you how can I fix it to make it working in the new version of the compiler?
Example code
Lets see a simplified version of generated (by my compiler) Haskell code:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
import Data.Tuple.OneTuple
------------------------------
-- data types
------------------------------
data Vector a = Vector {x :: a, y :: a, z :: a} deriving (Show)
-- the Vector_testid is used as wrapper over a function "testid".
newtype Vector_testid a = Vector_testid a
------------------------------
-- sample function, which is associated to data type Vector
------------------------------
testid (v :: Vector a) x = x
------------------------------
-- problematic function (described later)
------------------------------
testx x = call (method1 x) $ OneTuple "test"
------------------------------
-- type classes
------------------------------
-- type class used to access "method1" associated function
class Method1 cls m func | cls -> m, cls -> func where
method1 :: cls -> m func
-- simplified version of type class used to "evaluate" functions based on
-- their input. For example: passing empty tuple as first argument of `call`
-- indicates evaluating function with default arguments (in this example
-- the mechanism of getting default arguments is not available)
class Call a b where
call :: a -> b
------------------------------
-- type classes instances
------------------------------
instance (out ~ (t1->t1)) => Method1 (Vector a) Vector_testid out where
method1 = (Vector_testid . testid)
instance (base ~ (OneTuple t1 -> t2)) => Call (Vector_testid base) (OneTuple t1 -> t2) where
call (Vector_testid val) = val
------------------------------
-- example usage
------------------------------
main = do
let v = Vector (1::Int) (2::Int) (3::Int)
-- following lines equals to a pseudocode of ` v.method1 "test" `
-- OneTuple is used to indicate, that we are passing single element.
-- In case of more or less elements, ordinary tuples would be used.
print $ call (method1 v) $ OneTuple "test"
print $ testx v
The code compiles and works fine with GHC 7.6. When I'm trying to compile it with GHC 7.7, I'm getting following error:
debug.hs:61:10:
Illegal instance declaration for
‛Method1 (Vector a) Vector_testid out’
The liberal coverage condition fails in class ‛Method1’
for functional dependency: ‛cls -> func’
Reason: lhs type ‛Vector a’ does not determine rhs type ‛out’
In the instance declaration for
‛Method1 (Vector a) Vector_testid out’
The error is caused by new rules of checking what functional dependencies can do, namely liberal coverage condition (as far as I know, this is coverage condition relaxed by using -XUndecidableInstances)
Some attemps to fix the problem
I was trying to overcome this problem by changing the definition of Method1 to:
class Method1 cls m func | cls -> m where
method1 :: cls -> m func
Which resolves the problem with functional dependencies, but then the line:
testx x = call (method1 x) $ OneTuple "test"
is not allowed anymore, causing a compile error (in both 7.6 and 7.7 versions):
Could not deduce (Method1 cls m func0)
arising from the ambiguity check for ‛testx’
from the context (Method1 cls m func,
Call (m func) (OneTuple [Char] -> s))
bound by the inferred type for ‛testx’:
(Method1 cls m func, Call (m func) (OneTuple [Char] -> s)) =>
cls -> s
at debug.hs:50:1-44
The type variable ‛func0’ is ambiguous
When checking that ‛testx’
has the inferred type ‛forall cls (m :: * -> *) func s.
(Method1 cls m func, Call (m func) (OneTuple [Char] -> s)) =>
cls -> s’
Probable cause: the inferred type is ambiguous
EDIT:
It is also impossible to solve this issue using type families (as far as I know). If we replace Method1 type class and instances with following code (or simmilar):
class Method1 cls m | cls -> m where
type Func cls
method1 :: cls -> m (Func cls)
instance Method1 (Vector a) Vector_testid where
type Func (Vector a) = (t1->t1)
method1 = (Vector_testid . testid)
We would get obvious error Not in scope: type variable ‛t1’, because type families does not allow to use types, which does not appear on LHS of type expression.
The final question
How can I make this idea work under GHC 7.7? I know the new liberal coverage condition allows GHC devs make some progress with type checking, but it should somehow be doable to port idea working in GHC 7.6 over never compiler version.
(without forcing user of my DSL to introduce any further types - everything so far, like type class instances, I'm genarating using Template Haskell)

This is not a bug in GHC 7.7. It was a long-standing bug in GHC when it allowed instances
that violate functional dependencies. It seems, fortunately, that this problem is finally fixed. The error message emitted by GHC 7.7 is quite detailed, pointing out the problem with your instance Method1 (Vector a) Vector_testid out. Recall the meaning of functional
dependencies. Given
class C a b | a -> b
it follows that if the types a, b and b1 are such that C a b and C a b1
both hold, it must be true that b and b1 are the same. Let's look at your instance:
Method1 (Vector a) Vector_testid (t1->t1)
If we have types b and b1 that satisfy Method1 (Vector Int) Vector_testid (b->b)
and Method1 (Vector a) Vector_testid (b1->b1), nothing at all implies that b and b1 must be the same. Hence your instance is ill-formed. The fact that GHC 7.6 and before accepted the program was a well-known bug in GHC (discussed about every year).
What you seem to be trying is to define something like
Method1 (Vector a) Vector_testid (forall t. t -> t)
Alas, this syntax is not allowed, although many worksrounds exist. One, for example, involves the Apply class (see the HList paper, for example). A simpler way is as follows
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
-- import Data.Tuple.OneTuple
newtype OneTuple x = OneTuple x deriving Show
------------------------------
-- data types
------------------------------
data Vector a = Vector {x :: a, y :: a, z :: a} deriving (Show)
-- testx x = call (method1 x) $ OneTuple "test"
testx x = call x Method1 $ OneTuple "test"
-- associate methods to classes
class Methods cls m x y | cls m x -> y where
call :: cls -> m -> x -> y
instance Methods (Vector a) Method1 x x where
call self _ x = x
data Method1 = Method1 -- method label

Related

Apply constraint within constraint in Haskell

Is there anyway to apply a constraint within another constraint such that this
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE KindSignatures #-}
module Test where
type Con a = (Num a, Show a)
type App c a b = (c a, c b)
program :: App Con a b => a -> b -> String
program a b = show a ++ " " ++ show (b+1)
will work?
Currently GHC is giving me the following errors:
[1 of 1] Compiling Test ( Test.hs, interpreted )
Test.hs:9:12: error:
• Expected a constraint, but ‘App Con a b’ has kind ‘*’
• In the type signature: program :: App Con a b => a -> b -> String
|
9 | program :: App Con a b => a -> b -> String
| ^^^^^^^^^^^
Test.hs:9:16: error:
• Expected kind ‘* -> *’, but ‘Con’ has kind ‘* -> Constraint’
• In the first argument of ‘App’, namely ‘Con’
In the type signature: program :: App Con a b => a -> b -> String
|
9 | program :: App Con a b => a -> b -> String
| ^^^
Failed, no modules loaded.
Thanks!
An easy way to fix this is to use the LiberalTypeSynonyms extension. This extension allows GHC to first treat the type synonyms as substitutions and only afterwards check that the synonyms are fully applied. Note that GHC can be a little silly at kind inference, so you'll need to be very clear with it (i.e., an explicit signature). Try this:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LiberalTypeSynonyms #-}
module Test where
import Data.Kind (Constraint)
type Con a = (Num a, Show a)
type App c a b = (c a, c b) :: Constraint
program :: App Con a b => a -> b -> String
program a b = show a ++ " " ++ show (b+1)
Before I understood that this could be solved with LiberalTypeSynonyms, I had a different solution, which I'll keep here in case anyone's interested.
Although the error message you're getting is a bit misleading, the fundamental problem with your code comes down to the fact that GHC does not support partial application of type synonyms, which you have in App Con a b. There are a few ways to fix this, but I find the simplest is to convert the type synonym constraint into a class constraint following this pattern:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
type Con' a = (Num a, Show a)
class Con' a => Con a
instance Con' a => Con a
You can use this definition of Con anywhere you were intending to use your old one.
If you're interested in how/why this works, it's basically a trick to get around GHC's lack of support for partial type synonym/family application for the particular cases where those type synonyms/families define simple constraints.
What we're doing is defining a class, and every class comes with a constraint of the same name. Now, notice that the class has no body, but critically, the class itself has a constraint (in the above case Con' a), which means that every instance of the class must have that same constraint.
Next, we make an incredibly generic instance of Con, one that covers any type so long as the constraint Con' holds on that type. In essence, this assures that any type that is an instance of Con' is also an instance of Con, and the Con' constraint on the Con class instance assures that GHC knows that anything that's an instance of Con also satisfies Con'. In total, the Con constraint is functionally equivalent to Con', but it can be partially applied. Success!
As another side note, the GHC proposal for unsaturated type families was recently accepted, so there may be a not-too-far-off future where these tricks are unnecessary because partial application of type families becomes allowed.
Haskell does not support type-level lambdas, nor partial application of type families / type synonyms. Your Con must always be fully applied, it can not passed unapplied to another type synonym.
At best, we can try to use "defunctionalization" as follows, effectively giving names to the type-level lambdas we need.
{-# LANGUAGE ConstraintKinds, KindSignatures, TypeFamilies #-}
import Data.Kind
-- Generic application operator
type family Apply f x :: Constraint
-- A name for the type-level lambda we need
data Con
-- How it can be applied
type instance Apply Con x = (Show x, Num x)
-- The wanted type-level function
type App c a b = (Apply c a, Apply c b)
-- Con can now be passed since it's a name, not a function
program :: App Con a b => a -> b -> String
program a b = show a ++ " " ++ show (b+1)
To call App with a different first argument, one would need to repeat this technique: define a custom dummy type name (like Con) and describe how to apply it (using type instance Apply ... = ...).

How do the various "..Instances" pragma's work together, and is there a way around my current problem?

Consider the following code:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
class X a
class Y a
instance Y Bool
instance (Y a) => X a
instance {-# OVERLAPPING #-} X Int
f :: (X a) => a -> a
f x = x
These LANGUAGE pragma's are needed to write the above instances.
Now, say we want to write a function g:
g :: (Y a) => a -> a
g = f
Without IncoherentInstances or adding {-# INCOHERENT #-} to one of the instances, this doesn't typecheck.
But when we do add this, and ask ghci
ghci> :t f
f :: Y a => a -> a
Suddenly the type of 'f' changed?
With this small example, programs still typecheck when I give f an Int (indicating that the above would be merely a 'visual bug', but in a bigger example the same does not typecheck, giving me an error like:
Could not deduce (Y a) arising from a use of 'f
(...)
from the context: (..., X a, ...)
This also happens when we say
h = f
and try to call h with an Int
:type f does not report the type of the defined entity f. It reports the type of the expression f. GHC tries really hard to stamp polymorphism out of expressions. In particular, using f in an expression triggers simplification of the X a constraint (as does using any definition with a constraint). Without IncoherentInstances, GHC refrains from using instance Y a => X a, because there is another instance that overlaps it, so GHC needs to wait to see which one it should use. This ensures coherence; the only X Int instance that is ever used is the explicitly "specialized" one. With IncoherentInstances, you say that you don't care about coherence, so GHC goes ahead and simplifies X a to Y a using the polymorphic instance whenever f appears in an expression. The weird behavior you see where sometimes GHC is OK with using X Int and sometimes complains that there is no Y Int is a result of GHC making different internal decisions about when it wants to simplify constraints (you did ask for incoherence!). The command for seeing the type of a definition is :type +v. :type +v f should show the type of f "as declared". Hopefully, you can also see that IncoherentInstances is a bad idea. Don't use it.

Constraint on method depends on instances in scope?

Consider this code:
{-# language FlexibleInstances, UndecidableInstances #-}
module Y where
class C m where
x :: m
instance {-# overlappable #-} Monoid m => C m where
x = mempty
instance C Int where
x = 53
What is the type of x?
λ :type x
x :: C m => m
So far — so good. Now remove the Int instance. What is the type of x?
λ :type x
x :: Monoid m => m
Surprise!
Why is this happening?
This behaviour is explained in the following blog post:
Opaque constraint synonyms
In short: GHC is smart enough to see that you have only one instance of the C typeclass and decided that it's the only possible instance, so every time it sees C m constraint, it replaces it with Monoid m because they are equivalent.
N.B. As #chi further explains in a comment:
When GHC finds a constraint C t, it tries to solve it. If if finds a matching instance (...) => C t where ..., the constraint is replaced with the context (...). This is repeated as much as possible. The final constraint appears in the type (or triggers a "unsolved" type error). This process is justified since there can only be at most one matching instance. Overlapping instances change this, and prevent this context reduction when multiple instances (in scope!) match, roughly. It is a fragile extension, to be used with some care.

Haskell instance signatures

I'm a complete newbie in Haskell so please be patient.
Let's say I've got this class
class Indexable i where
at :: i a p -> p -> a
Now let's say I want to implement that typeclass for this data type:
data Test a p = Test [a]
What I tried is:
instance Indexable Test where
at (Test l) p = l `genericIndex` p
However it didn't compile, because p needs to be an Integral, however as far as I understand, it's impossibile to add the type signature to instances. I tried to use InstanceSigs, but failed.
Any ideas?
here is a version where you add the index-type to the class using MultiParamTypeClasses
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
module Index where
import Data.List (genericIndex)
class Indexable i f where
at :: forall a . f a -> i -> a
data Test a = Test [a]
instance Integral i => Indexable i Test where
at (Test as) i = as `genericIndex` i
here I need the FlexibleInstances because of the way the instance is declared and RankNTypes for the forall a . ;)
assuming this is your expected behavior:
λ> let test = Test [1..5]
λ> test `at` 3
4
λ> test `at` 0
1
λ> test `at` (0 :: Int)
1
λ> test `at` (1 :: Integer)
2
Just for fun, here's a very different solution which doesn't require any changes to your class declaration. (N.B. This answer is for fun only! I do not advocate keeping your class as-is; it seems a strange class definition to me.) The idea here is to push the burden of proof off from the class instance to the person constructing a value of type Test p a; we will demand that constructing such a value will require an Integral p instance in scope.
All this code stays exactly the same (but with a new extension turned on):
{-# LANGUAGE GADTs #-}
import Data.List
class Indexable i where
at :: i a p -> p -> a
instance Indexable Test where
at (Test l) p = l `genericIndex` p
But the declaration of your data type changes just slightly to demand an Integral p instance:
data Test a p where
Test :: Integral p => [a] -> Test a p
You are actually trying to do something fairly advanced. If I understand what you want, you actually need a multiparameter typeclass here, because your type parameter "p" depends on "i": for a list indexed by integer you need "p" to be integral, but for a table indexed by strings you need it to be "String", or at least an instance of "Ord".
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-} -- Enable the language extensions.
class Indexable i p | i -> p where
at :: i a -> p -> a
This says that the class is for two types, "i" and "p", and if you know "i" then "p" follows automatically. So if "i" is a list the "p" has to be Int, and if "i" is a "Map String a" then "p" has to be "String".
instance Indexable [a] Int where
at = (!!)
This declares the combination of [a] and Int as being an instance of Indexable.
user2407038 has provided an alternative approach using "type families", which is a more recent and sophisticated version of multiparameter type classes.
You can use associated type families and constraint kinds:
import GHC.Exts(Constraint)
class Indexable i where
type IndexableCtr i :: * -> Constraint
at :: IndexableCtr i p => i a p -> p -> a
instance Indexable Test where
type IndexableCtr Test = Integral
at (Test l) p = l `genericIndex` p
This defines the class Indexable with an associated type IndexableCtr which
is used to constraint the type of at.

Is the dispatch of a Haskell TypeClass dynamic?

Given the following Haskell code snapshot:
class Foo a where
bar :: a -> ...
quux :: a -> ...
...
Where the value of a is determined at runtime - the class dispatches on this value.
I'm assuming that the compiler can statically check the types at compile-time, and ensure that no invalid types can dispatch on it.
Now if we compare this to a dynamic dispatch in Java:
interface Flippable {
Flippable flip();
}
class Left implements Flippable {
Right flip();
}
class Right implements Flippable {
Left flip();
}
class Demo {
public static void main(String args[]) {
Flippable flippable = new Right();
System.out.println(flippable.flip);
}
}
Assumptions:
Haskell can dispatch on return type as well as multiple arguments making dispatch different to other languages.
My question is: Is the dispatch of a Haskell TypeClass dynamic?
If your code is Haskell 2010, with no language extensions turned on, Haskell actually doesn't support run-time polymorphism at all!
That's quite surprising. Haskell feels like a very polymorphic language. But in fact, all the types can in principle be decided purely at compile-time. (GHC chooses not to, but that's an implementation detail.)
This is exactly the same situation as C++ templates. When you write something like std::vector<int>, the compiler knows, at compile-time, all the times involved. The really surprising thing is just how rarely you actually need true run-time polymorphism!
Now, there are scenarios where you want to run different code based on run-time circumstances. But in Haskell, you can do that just by passing a function as an argument; you don't need to create a "class" (in the OOP sense) merely to achieve this.
Now, if you turn on some language extensions (most conspicuously ExistentialQuantification) then you get true, run-time polymorphism.
Note that the main reason people seem to do this is so you can do
class Foo f where
bar :: f -> Int
baz :: f -> Bool
data AnyFoo = forall f. Foo => AnyFoo f
my_list :: [AnyFoo]
...
This is widely considered a Haskell anti-pattern. In particular, if you upcast stuff in Java to put it into a list, you then later downcast it again. But the code above offers no possibility to ever downcast. You also can't use run-time reflection (since Haskell doesn't have that either). So really, if you have a list of AnyFoo, the only thing you can do with it is call foo or bar on it. So... why not just store the result of foo and bar?
data AnyFoo = AnyFoo {foo :: Int, bar :: Bool}
It lets you do exactly the same stuff, but doesn't require any non-standard extensions. In fact, in some ways, it's actually a bit more flexible. You now don't even need a Foo class, you don't need to define a new type for every sort of Foo you might have, just a function that constructs the AnyFoo data structure for it.
It depends what you mean by "dynamic" dispatch. There aren't subtyping in haskell, so your Java example is hard to translate.
In situation when you have type class, say Show and want to put different elements into the list, you can use existential quantification:
{-# LANGUAGE ExistentialQuantification #-}
data Showable = forall a. Show a => Showable a
instance Show Showable where
show (Showable x) = show x
test :: main ()
test = let list = [Showable True, Showable "string"]
in print list
-- >>> test
-- [True,"string"]
Here you can say that dispatch happens "dynamically". It happens in the same way as in C++ or Java. The Show dictionary is carried with an object, like a vtable in C++ (or class definition ptr in Java, dunno how it's called).
Yet, as #MathematicalOrchid explained, this is an anti-pattern.
Yet if you want to flip from Left to Right and back, you can state that in type class definition.
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FunctionalDependencies #-}
class Flippable a b | a -> b where
flip' :: Flippable b a => a -> b
newtype INL = INL Int deriving Show
newtype INR = INR Int deriving Show
instance Flippable INL INR where
flip' (INL x) = INR x
instance Flippable INR INL where
flip' (INR x) = INL x
-- >>> flip' $ INL 1
-- INR 1
-- >>> flip' $ flip' $ INL 1
-- INL 1
In this case flip' calls are resolved already at compile-time.
You could have have class Flip a where flip' :: a -> Flippable using existential quantification too. Then consecutive calls will be dispatched dynamically. As always, it depends on your needs.
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE StandaloneDeriving #-}
class Flip a where
flip' :: a -> Flippable
-- Show is only for repl purposes
data Flippable = forall a. (Flip a, Show a) => Flippable a
deriving instance Show Flippable
instance Flip Flippable where
flip' (Flippable x) = flip' x
newtype INL = INL Int deriving Show
newtype INR = INR Int deriving Show
instance Flip INL where
flip' (INL x) = Flippable (INR x)
instance Flip INR where
flip' (INR x) = Flippable (INL x)
-- >>> flip' $ flip' $ flip' $ INL 1
-- Flippable (INR 1)
Hopefully this answers your question.

Resources