Type annotation breaks function - haskell

Consider the following declarations for a function f' using singletons with the Frames library (which defines UnColumn and AllAre), and a wrapper function using withSing.
{-# LANGUAGE AllowAmbiguousTypes -#}
import Frames
import Data.Singletons.Prelude
f' :: forall rs1 rs2 a. (AllAre a (UnColumn rs1), AllAre a (UnColumn rs2), Num a)
=> SList rs1 -> SList rs2 -> Frame (Record rs1) -> Frame (Record rs2) -> Int
f' = undefined
f df1 df2 = withSing (withSing f') df1 df2
This seems to work fine. But when I add a type annotation, type checking fails with the error Could not deduce: (AllAre a0 (UnColumn rs1), AllAre a0 (UnColumn rs2)).
f :: (SingI rs1, SingI rs2, AllAre a (UnColumn rs2), AllAre a (UnColumn rs1), Num a)
=> Frame (Record rs1) -> Frame (Record rs2) -> Int
f df1 df2 = withSing (withSing f') df1 df2
The thing is, this is precisely the inferred type signature, according to GHCi (well, Intero). To my understanding adding an explicit signature matching the inferred signature should have no impact on the code semantics, so why would this break the code?

As a general rule of thumb, adding an explicit type signature that matches the inferred type to a Haskell program will not change its meaning, but it's not actually guaranteed in the general case. (I believe it is guaranteed for top-level definitions in Haskell98, though.)
Ultimately, your problem isn't much different from the sort of type variable scoping problem that can happen with local definitions in Haskell98:
import Data.List
sortImage :: Ord b => (a -> b) -> [a] -> [a]
sortImage f = sortBy cmp
where cmp x y = compare (f x) (f y)
Here, the inferred type of cmp is effectively (Ord b) => a -> a -> Ordering. You can't make this signature explicit, though, because you can't tie a and b back to the outer signature (and the type of f in particular) unless you use ScopedTypeVariables, in which case you can write:
sortImage :: forall a b . Ord b => (a -> b) -> [a] -> [a]
sortImage f = sortBy cmp
where cmp :: a -> a -> Ordering
cmp x y = compare (f x) (f y)
As you've discovered, you can make this sort of type variable scoping problem happen with top level definitions, too, at least with AllowAmbiguousTypes enabled.
Here is a simpler example that illustrates what I believe is the same problem, adapted from the GHC documentation on the AllowAmbiguousTypes extension:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
class D a b
instance D Bool b
instance D Int b
strange :: D a b => a -> a
strange = undefined
-- stranger :: (D a b1, D a b) => a -> a
stranger x = strange (strange x)
I've shown the inferred type of stranger as a comment. If you try to make it explicit, you'll get the error:
• Could not deduce (D a b0) arising from a use of ‘strange’
from the context: (D a b2, D a b)
The issue is that GHC can infer that stranger can be called on any a that satisfies D a b1 for the outer strange :: D a b1 => a -> a and also satisfies D a b for the inner strange :: D a b => a -> a.
However, if you attempt to make this type signature explicit, the link between the b1 and b variables in the explicit signature for stranger and their relationship to the types of the strange calls is lost, much as the relationship between the a and b in a hypothetical cmp signature and the a and b in the sortImage signature is lost in the first example.
Using ScopedTypeVariables alone isn't enough to solve the problem here because, constraints aside, the type of strange is just a -> a and doesn't directly reference b. So, you can write:
stranger :: forall a b1 b2 . (D a b1, D a b2) => a -> a
stranger x = (strange :: a -> a) ((strange :: a -> a) x)
but you can't tie the b1 and b2 to the types of the strange calls. You need TypeApplications to do that:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
class D a b
instance D Bool b
strange :: forall a b . D a b => a -> a
strange = id
stranger :: forall a b1 b2 . (D a b1, D a b2) => a -> a
stranger x = (strange #a #b1) (strange #a #b2 x)
and then it type checks okay, and you can even call:
> stranger False
False
without any type annotations (which is somewhat surprising). If you had an instance:
instance D Int Double
though, then you'd need to be explicit to use stranger on Ints:
> stranger #_ #Double #Double (1 :: Int)

Related

Is it possible to write an alias for coerce?

Let's say for the purposes of this question I want to make an alias of coerce. I start with the obvious
import Data.Coerce
q = coerce
a bit surprisingly this gives rise an error:
coerce.hs:3:5: error:
• Couldn't match representation of type ‘a0’ with that of ‘b0’
arising from a use of ‘coerce’
• In the expression: coerce
In an equation for ‘q’: q = coerce
• Relevant bindings include q :: a0 -> b0 (bound at coerce.hs:4:1)
|
4 | q = coerce
| ^^^^^^
This error is quite opaque so I slapped the type signature1 of coerce onto q:
{-# Language RankNTypes #-}
{-# Language KindSignatures #-}
{-# Language PolyKinds #-}
import Data.Coerce
import GHC.Exts
q :: forall (k :: RuntimeRep) (a :: TYPE k) (b :: TYPE k). Coercible a b => a -> b
q = coerce
But this gives rise to the error:
coerce.hs:8:5: error:
Cannot use function with levity-polymorphic arguments:
coerce :: a -> b
Levity-polymorphic arguments: a :: TYPE k
|
8 | q = coerce
| ^^^^^^
This error is not very helpful. It informs me there is an issue with levity polymorphism and that is about it.
What is really quite curious to me is that when I make q bottom:
{-# Language RankNTypes #-}
{-# Language KindSignatures #-}
{-# Language PolyKinds #-}
import Data.Coerce
import GHC.Exts
q :: forall (k :: RuntimeRep) (a :: TYPE k) (b :: TYPE k). Coercible a b => a -> b
q = q
The error goes away and the code compiles fine.
I'm left unsure whether such an alias is possible, or what even the issue with the alias is.
Is such an alias possible where q maintains the type of coerce? What issue is the compiler running into with my code?
1: As pointed out by the comments this type signature only has levity polymorphism in since base-4.13 or ghc 8.8. For the purposes of this question we want the levity polymorphism.
#dfeuer's answer covers a workaround, but I think issue #17670 explains why this is happening. Because coerce is a primop, it must be fully saturated, so any use is implicitly eta-expanded. When you write:
q = coerce
you're really writing:
q = \x -> coerce x
The initial error message you get is actually a result of the monomorphism restriction. If you write either:
q x = coerce x
or add the NoMonomorphismRestriction extension, the program is accepted. Unfortunately, the resulting q isn't levity polymorphic. It's instantiated with lifted types.
If try to force the issue by adding an appropriate polymorphic type signature:
q :: forall (k :: RuntimeRep) (a :: TYPE k) (b :: TYPE k). Coercible a b => a -> b
q = coerce
then bleeding edge versions of GHC (e.g., "8.11" built from source last month) give an elaborated error message:
BadCoerce.hs:11:5: error:
Cannot use function with levity-polymorphic arguments:
coerce :: a -> b
(Note that levity-polymorphic primops such as 'coerce' and unboxed tuples
are eta-expanded internally because they must occur fully saturated.
Use -fprint-typechecker-elaboration to display the full expression.)
Levity-polymorphic arguments: a :: TYPE k
Ultimately, you're running up against the prohibition that no variable (in this case an implicit variable introduced to eta-expand coerce) is permitted to be levity polymorphic. The reason q = q works is that there's no eta expansion and so no variable involved. Try q x = q x and it will fail with "a levity-polymorphic type is not allowed here" error message.
It doesn't look like this is possible, but you can get really close. Note: it may well be possible to shorten this.
blop
:: forall (k :: RuntimeRep) (a :: TYPE k) (b :: TYPE k) q r.
Coercible a b
=> q :~: (a -> a)
-> r :~: (a -> b)
-> Coercion q r
blop Refl Refl = Coercion
bloverce
:: forall (k :: RuntimeRep) (a :: TYPE k) (b :: TYPE k) q r.
Coercible a b
=> q :~: (a -> a)
-> r :~: (a -> b)
-> q -> r
bloverce qaa rab = case blop qaa rab of Coercion -> coerce
gloerce
:: forall (r :: RuntimeRep).
(forall (x :: TYPE r). x -> x) -> Coe r
gloerce kid = Coe (bloverce Refl Refl (kid :: a -> a) :: forall (a :: TYPE r) (b :: TYPE r). Coercible a b => a -> b)
newtype Coe (r :: RuntimeRep) = Coe (forall (a :: TYPE r) (b :: TYPE r). Coercible a b => a -> b)
As long as you can provide the polymorphic identity function for a certain runtime representation, you can use gloerce to get its coerce.
Of course, this is all fairly silly in practice: in the rare cases when you need a representation-polymorphic coercion function, you can just use coerce directly.

Letting a distributed DSL implementation choose its serialization format (via constraint family)

I'm writing a distributed programming DSL and I'd like to allow implementations to choose their serialization method (if any, as it might not even be needed for a simulated execution).
Trying to solve this by adding a type family led to the problem below for a standard function I have. I imagine that it would work if I could require, and have the type checker understand, that if two values are serializable their pairing is also serializable. However, adding that as a quantified constraint doesn't seem to work. Can this be solved or is there a better solution for the problem?
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Kind
class (Monad (DistrM t)) => Distributed (t :: *) where
type Sendable t :: * -> Constraint
type DistrM t :: * -> *
-- ...
data FromSendable t a where
FromSendable :: (Sendable t b)
=> (b -> DistrM t a)
-> b
-> FromSendable t a
pairWith :: ( Sendable t a
, Distributed t
, forall a b. (Sendable t a, Sendable t b) => Sendable t (a,b)
)
=> a
-> FromSendable t b
-> FromSendable t (a,b)
pairWith a (FromSendable f b) =
FromSendable (\(a,b) -> (a,) <$> f b) (a,b)
-- >>> Could not deduce: Sendable t (a1, b1) ...
Edit 1
It type checks if I do
pairWith :: ( Sendable t a
, Distributed t
, st ~ Sendable t
, forall a b. (st a, st b) => st (a,b)
)
=> ...
It would get cumbersome to have to repeat these types of constraints, so I tried a type synonym but that doesn't work:
type Cs t = forall (st :: * -> Constraint).
(Sendable t ~ st, forall a b. (st a, st b) => st (a,b))
-- >>> Expected a constraint, but ‘st (a, b)’ has kind ‘*’
This looks weird. I only have a partial answer, but I'll post it anyway.
I simplified your code to
class C t where -- (*)
data T t where
T :: C t => (a -> t) -> a -> T t
foo ::
( C u
, forall a b . (C a , C b) => C (a, b) )
=> u -> T t -> T (u, t)
foo i (T f x) = T (\(a,b) -> (a, f b)) (i, x)
and, in this version, it compiles fine. However, if we replace
class C t where
with
type instance C :: * -> Constraint
then we get an error telling us that C (a, b) can not be deduced.
I can't completely understand what's going on here, but it looks like quantified constraints do not mix well with type families.
It looks like the above type family is treated like it were
type instance C (t :: *) :: Constraint
and in such case, I can't understand what's wrong. Since C now does not refer to a single type class, it is impossible to implement a quantified constraint like forall a b . (C a , C b) => C (a, b) by (say) passing a pointer to a specific instance, since the three C constraints could be anything at all, in an open world.
I still do not understand why type family C :: * -> Constraint is handled in the same way.
Perhaps GHC should reject quantified constraints involving type families ... -> Constraint in such way? I not sure.
I think you've pushed your code to the edges of GHC's type system here. You can fix the kind error on Cs by writing:
type Cs t = (forall (st :: * -> Constraint).
(Sendable t ~ st, forall a b. (st a, st b) => st (a,b))) :: Constraint
but then you run up against "GHC doesn't yet support impredicative polymorphism". Until GHC adds support for class families as per issue 14860, you're maybe out of luck with this approach.
However, you did ask about alternative approaches. Doesn't making Sendable t a a multiparameter type class accomplish basically the same thing?
Certainly, the following type-checks:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Kind
class (Monad (DistrM t)) => Distributed (t :: *) where
type DistrM t :: * -> *
-- ...
class Sendable t a where
data FromSendable t a where
FromSendable :: (Sendable t b)
=> (b -> DistrM t a)
-> b
-> FromSendable t a
type Cs t = forall a b. (Sendable t a, Sendable t b) => Sendable t (a,b) :: Constraint
pairWith :: ( Sendable t a
, Distributed t
, Cs t
)
=> a
-> FromSendable t b
-> FromSendable t (a,b)
pairWith a (FromSendable f b) =
FromSendable (\(a,b) -> (a,) <$> f b) (a,b)

Polymorphic "flip" fails in 7.10

The monomorphic library contains the following snippet (which should hopefully compile in 7.8):
{-# LANGUAGE DataKinds, ExistentialQuantification, FlexibleContexts, GADTs #-}
{-# LANGUAGE ImpredicativeTypes, PolyKinds, RankNTypes, TypeFamilies #-}
{-# LANGUAGE TypeOperators, UndecidableInstances #-}
class Monomorphicable k where
type MonomorphicRep k :: *
withPolymorphic :: Monomorphicable k
=> MonomorphicRep k -> (forall a. k a -> b) -> b
withPolymorphic k trans = undefined
-- | Flipped version of 'withPolymorphic'.
liftPoly :: Monomorphicable k
=> (forall a. k a -> b) -> MonomorphicRep k -> b
liftPoly = flip withPolymorphic
However in 7.10, GHC complains:
Couldn't match type ‘k2 a0 -> b’ with ‘forall (a :: k0). k1 a -> b’
Expected type: MonomorphicRep k2 -> (k2 a0 -> b) -> b
Actual type: MonomorphicRep k1
-> (forall (a :: k0). k1 a -> b) -> b
Relevant bindings include
liftPoly :: (forall (a :: k). k2 a -> b) -> MonomorphicRep k2 -> b
(bound at Data/Type/Monomorphic.hs:45:1)
In the first argument of ‘flip’, namely ‘withPolymorphic’
In the expression: flip withPolymorphic
Of course if I changed the definition of liftPoly to
liftPoly a b = withPolymorphic b a
then 7.10 is happy. What's going on here? Is 7.10 supposed to be stricter when dealing with polymorphic functions somehow? It doesn't appear to be the monomorphism restriction since everything has a signature.
The type of flip is
flip :: (x -> y -> z) -> (y -> x -> z)
To type check liftPoly, we have to instantiate the variable y at the polymorphic type forall a. k a -> b. This is an instance of impredicative polymorphism.
As the page at https://ghc.haskell.org/trac/ghc/wiki/ImpredicativePolymorphism says,
We've made various attempts to support impredicativity, so there is a flag -XImpredicativeTypes. But it doesn't work, and is absolutely unsupported. If you use it, you are on your own; I make no promises about what will happen.
So, don't be too surprised when the behavior of ImpredicativeTypes changes between versions of GHC.

How to put constraints on type variable of kind `Constraint`?

I'm playing around with the ConstraintKinds extension of GHC.
I have the following data type, which is just a box for things fulfilling some one parameter constraint c:
data Some (c :: * -> Constraint) where
Some :: forall a. c a => a -> Some c
For example, I could construct a box with some kind of number (arguably not very useful).
x :: Some Num
x = Some (1 :: Int)
Now, as long as c includes the constraint Show, I could provide an instance of Show (Some c).
instance ??? => Show (Some c) where
show (Some x) = show x -- Show dictionary for type of x should be in scope here
But how do I express this requirement in the instance context (marked with ???)?
I cannot use an equality constraint (c ~ Show), because the two are not necessarily equal. c could be Num, which implies, but is not equal to, Show.
Edit
I realised that this cannot be possible in general.
If you have two values of type Some Eq, it is not possible to compare them for equality. They could be of different types that each have their own notion of equality.
What applies to Eq applies to any type class in which the type parameter appears on the right hand side of the first function arrow (like the second a in (==) :: a -> a -> Bool).
Considering that there is no way to create a constraint expressing "this type variable is not used beyond the first arrow", I don't think it is possible to write the instance I want to write.
The closest we are able to get is a Class1 class that reifys the relationship between a class and a single superclass constraint as a class. It's based on the Class from constraints.
First, we'll take a short tour of the constraints package. A Dict captures the dictionary for a Constraint
data Dict :: Constraint -> * where
Dict :: a => Dict a
:- captures that one constraint entails another. If we have a :- b, whenever we have the constraint a we can produce the dictionary for the constraint b.
newtype a :- b = Sub (a => Dict b)
We need a proof similar to :-, we need to know that forall a. h a :- b a, or h a => Dict (b a).
Single Inheritance
Actually implementing this for classes with just single inheritance requires the kitchen sink of language extensions, including OverlappingInstances.
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances #-}
import Data.Constraint
We'll define the class of constraints of kind k -> Constraint where the constraint has a single superclass.
class Class1 b h | h -> b where
cls1 :: h a :- b a
We're now equipped to tackle our example problem. We have a class A that requires a Show instance.
class Show a => A a
instance A Int
Show is a superclass of A
instance Class1 Show A where
cls1 = Sub Dict
We want to write Show instances for Some
data Some (c :: * -> Constraint) where
Some :: c a => a -> Some c
We can Show a Some Show.
instance Show (Some Show) where
showsPrec x (Some a) = showsPrec x a
We can Show a Some h whenever h has a single superclass b and we could show Some b.
instance (Show (Some b), Class1 b h) => Show (Some h) where
showsPrec x (Some (a :: a)) =
case cls1 :: h a :- b a of
Sub Dict -> showsPrec x ((Some a) :: Some b)
This lets us write
x :: Some A
x = Some (1 :: Int)
main = print x
The new QuantifiedConstraints extension allows this.
class (a => b) => Implies a b where
instance (a => b) => Implies a b where
instance (forall a. c a `Implies` Show a) => Show (Some c) where
show (Some x) = show x
Within the body of the Show instance, it is as if there is a
instance forall a. Implies (c a) (Show a)
in scope. If you then have T :: Type and know c T, then the superclass of c T => Show T of the specialized Implies (c T) (Show T) instance allows you to derive Show T. It is necessary to use Implies instead of a straight forall a. c a => Show a constraint. This incorrect constraint acts like
instance forall a. c a => Show a
which overlaps with every Show instance, causing weird breakage. Forcing an indirection through the superclass of an otherwise useless constraint fixes everything.
You cannot make Some c an instance of Show, except trivially.
You want to show the a inside Some, but that variable is existentially quantified, so we cannot depend on any knowledge of the type of a. In particular, we have no way of knowing that a is an instance of Show.
EDIT: I'll expand on my answer.
Even with more machinery, and giving up on a Show instance, I still don't think what you want is possible because of the existential quantification.
First I'll rewrite Some in a more familiar form
data Dict p where
Dict :: p a => a -> Dict p
The usual way to talk about "constraints implying constraints" is with the concept of constraint entailment.
data p :- q where
Sub :: p a => Dict q -> p :- q
We can think about a value of type p :- q as a proof that if the constraint forall a. p a holds, then forall a. q a follows.
Now we try to write a sensible show-ish function
showD :: p :- Show -> Dict p -> String
showD (Sub (Dict a)) (Dict b) = show b
At a glance, this might work. We have brought the following constraints into scope (forgive the pseudo-exists syntax)
(0) p :: * -> Constraint
(1) exists a. p a -- (Dict p)
(2) exists b. p b => Show b -- (p :- Show)
But now things fall apart, GHC rightfully complains:
main.hs:10:33:
Could not deduce (Show a2) arising from a use of `show'
from the context (p a)
bound by a pattern with constructor
Sub :: forall (p :: * -> Constraint) (q :: * -> Constraint) a.
(p a) =>
Dict q -> p :- q,
in an equation for `showD'
at main.hs:10:8-19
or from (Show a1)
bound by a pattern with constructor
Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p,
in an equation for `showD'
at main.hs:10:13-18
or from (p a2)
bound by a pattern with constructor
Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p,
in an equation for `showD'
at main.hs:10:23-28
because it is impossible to unify the a from (1) with the b from (2).
This is the same essential idea that is used throughout the constraints package mentioned in the comments.

Binding type variables that only occur in assertions

I find it extremely difficult to describe my problem, so here goes nothing:
I have a bunch of assertions on the type of a function. These assertions rely on a type variable that is not used for any parameter of the function, but is only used for internal bindings. Whenever I use this function it does not compile because, of course, the compiler has no information from which to guess what type to bind my type variable. Here is the code:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables,
TypeOperators, TypeSynonymInstances #-}
class C a a' where convert :: a -> a'
class F a b where apply :: a -> b
class S s a where select :: s -> a
data CInt = CInt Int
instance S (Int,String) Int where select (i,_) = i
instance F Int CInt where apply = CInt
f :: forall s a b . (S s a, F a b) => s -> b
f s =
let v = select s :: a
y = apply v :: b
in y
x :: Int
x = f (10,"Pippo")
And here is the generated error:
FunctorsProblems.hs:21:4:
No instances for (F a Int, S (t, [Char]) a)
arising from a use of `f' at FunctorsProblems.hs:21:4-17
Possible fix:
add an instance declaration for (F a Int, S (t, [Char]) a)
In the expression: f (10, "Pippo")
In the definition of `x': x = f (10, "Pippo")
Failed, modules loaded: none.
Prelude>
You are trying to intersect some set of instances of classes and for compiler there is no way to say that this intersection will be empty or single entry.
You want to force compiler to choose the right type for you without knowing which problems (information loss or complexity of calculations) that decision can bring in your program. If you want to do that you should give a hint to compiler what is the best type "a" for specific pair "s" and "b" (with us of that FunctionalDependencies you specified).
class E x a | x -> a
instance (S s Int, F Int CInt) => E (s, CInt) Int
f :: forall s a b . (E (s,b) a) => s -> b
Probably there is the way to specify order of preferred types of "a" for pair of "s" and "b" with further deduce of best "a" (i.e. use of type-level or something like that to attach that information).

Resources