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.
Related
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.
I don't understand why the following code won't compile:
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
data A = A
class C a where
c :: a -> Bool
instance C A where
c _ = True
data D a where
D :: C a => D a
toBool :: D a -> Bool
toBool D = c (undefined::a)
Here is the error message:
Could not deduce (C a0) arising from a use of ‘c’
from the context (C a)
bound by a pattern with constructor
D :: forall a. C a => D a,
in an equation for ‘toBool’
at test.hs:15:8
The type variable ‘a0’ is ambiguous
Note: there is a potential instance available:
instance C A -- Defined at test.hs:8:10
In the expression: c (undefined :: a)
In an equation for ‘toBool’: toBool D = c (undefined :: a)
Can someone explain what's going on ?
The type variables introduced in a top-level type declaration are not the same as those introduced inside the body of the function. Another way of saying this is the nested type declarations introduce "fresh" variables. Another another way to say this is to put explicit foralls in your code where Haskell automatically introduces them, silently:
toBool :: forall a . D a -> Bool
toBool D = c (undefined :: forall a . a) -- another forall here?
What you really intended was
toBool :: forall a . D a -> Bool
toBool D = c (undefined :: a) -- capture `a` from prior scope
and, you're in luck. It turns out that almost everyone needs this kind of functionality from time to time so a very common Haskell extension exists called ScopedTypeVariables. The following code ought to compile
{-# LANGUAGE ScopedTypeVariables #-}
toBool :: forall a . D a -> Bool
toBool D = c (undefined :: a)
Note that in order to invoke ScopedTypeVariables you must now manually introduce the foralls that you want to be treated specially. Without that manual forall Haskell will automatically introduce them at all the same locations it normally does.
I'm generalizing this n-ary complement to an n-ary compose, but I'm having trouble making the interface nice. Namely, I can't figure out how to use numeric literals at the type level while still being able to pattern match on successors.
Rolling my own nats
Using roll-my-own nats, I can make n-ary compose work, but I can only pass n as an iterated successor, not as a literal:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
module RollMyOwnNats where
import Data.List (genericIndex)
-- import Data.Proxy
data Proxy (n::Nat) = Proxy
----------------------------------------------------------------
-- Stuff that works.
data Nat = Z | S Nat
class Compose (n::Nat) b b' t t' where
compose :: Proxy n -> (b -> b') -> t -> t'
instance Compose Z b b' b b' where
compose _ f x = f x
instance Compose n b b' t t' => Compose (S n) b b' (a -> t) (a -> t') where
compose _ g f x = compose (Proxy::Proxy n) g (f x)
-- Complement a binary relation.
compBinRel :: (a -> a -> Bool) -> (a -> a -> Bool)
compBinRel = compose (Proxy::Proxy (S (S Z))) not
----------------------------------------------------------------
-- Stuff that does not work.
instance Num Nat where
fromInteger n = iterate S Z `genericIndex` n
-- I now have 'Nat' literals:
myTwo :: Nat
myTwo = 2
-- But GHC thinks my type-level nat literal is a 'GHC.TypeLits.Nat',
-- even when I say otherwise:
compBinRel' :: (a -> a -> Bool) -> (a -> a -> Bool)
compBinRel' = compose (Proxy::Proxy (2::Nat)) not
{-
Kind mis-match
An enclosing kind signature specified kind `Nat',
but `2' has kind `GHC.TypeLits.Nat'
In an expression type signature: Proxy (2 :: Nat)
In the first argument of `compose', namely
`(Proxy :: Proxy (2 :: Nat))'
In the expression: compose (Proxy :: Proxy (2 :: Nat)) not
-}
Using GHC.TypeLits.Nat
Using GHC.TypeLits.Nat, I get type-level nat literals, but there is no successor constructor that I can find, and using the type function (1 +) doesn't work, because GHC (7.6.3) can't reason about injectivity of type functions:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module UseGHCTypeLitsNats where
import GHC.TypeLits
-- import Data.Proxy
data Proxy (t::Nat) = Proxy
----------------------------------------------------------------
-- Stuff that works.
class Compose (n::Nat) b b' t t' where
compose :: Proxy n -> (b -> b') -> t -> t'
instance Compose 0 b b' b b' where
compose _ f x = f x
instance (Compose n b b' t t' , sn ~ (1 + n)) => Compose sn b b' (a -> t) (a -> t') where
compose _ g f x = compose (Proxy::Proxy n) g (f x)
----------------------------------------------------------------
-- Stuff that does not work.
-- Complement a binary relation.
compBinRel , compBinRel' :: (a -> a -> Bool) -> (a -> a -> Bool)
compBinRel = compose (Proxy::Proxy 2) not
{-
Couldn't match type `1 + (1 + n)' with `2'
The type variable `n' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
In the expression: compose (Proxy :: Proxy 2) not
In an equation for `compBinRel':
compBinRel = compose (Proxy :: Proxy 2) not
-}
{-
No instance for (Compose n Bool Bool Bool Bool)
arising from a use of `compose'
The type variable `n' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there is a potential instance available:
instance Compose 0 b b' b b'
-}
compBinRel' = compose (Proxy::Proxy (1+(1+0))) not
{-
Couldn't match type `1 + (1 + 0)' with `1 + (1 + n)'
NB: `+' is a type function, and may not be injective
The type variable `n' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Expected type: Proxy (1 + (1 + 0))
Actual type: Proxy (1 + (1 + n))
In the first argument of `compose', namely
`(Proxy :: Proxy (1 + (1 + 0)))'
-}
I agree that semantic editor combinators are more elegant and more general here -- and concretely, it will always be easy enough to write (.) . (.) . ... (n times) instead of compose (Proxy::Proxy n) -- but I'm frustrated that I can't make the n-ary composition work as well as I expected. Also, it seems I would run into similar problems for other uses of GHC.TypeLits.Nat, e.g. when trying to define a type function:
type family T (n::Nat) :: *
type instance T 0 = ...
type instance T (S n) = ...
UPDATE: Summary and adaptation of the accepted answer
There's a lot of interesting stuff going on in the accepted answer,
but the key for me is the Template Haskell trick in the GHC 7.6
solution: that effectively lets me add type-level literals to my GHC
7.6.3 version, which already had injective successors.
Using my types above, I define literals via TH:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DataKinds #-}
module RollMyOwnLiterals where
import Language.Haskell.TH
data Nat = Z | S Nat
nat :: Integer -> Q Type
nat 0 = [t| Z |]
nat n = [t| S $(nat (n-1)) |]
where I've moved my Nat declaration into the new module to avoid an
import loop. I then modify my RollMyOwnNats module:
+import RollMyOwnLiterals
...
-data Nat = Z | S Nat
...
+compBinRel'' :: (a -> a -> Bool) -> (a -> a -> Bool)
+compBinRel'' = compose (Proxy::Proxy $(nat 2)) not
Unfortunately your question cannot be answered in principle in the currently released version of GHC (GHC 7.6.3) because of a consistency problem pointed out in the recent message
http://www.haskell.org/pipermail/haskell-cafe/2013-December/111942.html
Although type-level numerals look like numbers they are not guaranteed to behave like numbers at all (and they don't). I have seen Iavor Diatchki and colleagues have implemented proper type level arithmetic in GHC (which as as sound as the SMT solver used as a back end -- that is, we can trust it). Until that version is released, it is best to avoid type level numeric literals, however cute they may seem.
EDIT: Rewrote answer. It was getting a little bulky (and a little buggy).
GHC 7.6
Since type level Nats are somewhat... incomplete (?) in GHC 7.6, the least verbose way of achieving what you want is a combination of GADTs and type families.
{-# LANGUAGE GADTs, TypeFamilies #-}
module Nats where
-- Type level nats
data Zero
data Succ n
-- Value level nats
data N n f g where
Z :: N Zero (a -> b) a
S :: N n f g -> N (Succ n) f (a -> g)
type family Compose n f g
type instance Compose Zero (a -> b) a = b
type instance Compose (Succ n) f (a -> g) = a -> Compose n f g
compose :: N n f g -> f -> g -> Compose n f g
compose Z f x = f x
compose (S n) f g = compose n f . g
The advantage of this particular implementation is that it doesn't use type classes, so applications of compose aren't subject to the monomorphism restriction. For example, compBinRel = compose (S (S Z)) not will type check without type annotations.
We can make this nicer with a little Template Haskell:
{-# LANGUAGE TemplateHaskell #-}
module Nats.TH where
import Language.Haskell.TH
nat :: Integer -> Q Exp
nat 0 = conE 'Z
nat n = appE (conE 'S) (nat (n - 1))
Now we can write compBinRel = compose $(nat 2) not, which is much more pleasant for larger numbers. Some may consider this "cheating", but seeing as we're just implementing a little syntactic sugar, I think it's alright :)
GHC 7.8
The following works on GHC 7.8:
-- A lot more extensions.
{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, GADTs, MultiParamTypeClasses, PolyKinds, TypeFamilies, TypeOperators, UndecidableInstances #-}
module Nats where
import GHC.TypeLits
data N = Z | S N
data P n = P
type family Index n where
Index 0 = Z
Index n = S (Index (n - 1))
-- Compose is defined using Z/S instead of 0, 1, ... in order to avoid overlapping.
class Compose n f r where
type Return n f r
type Replace n f r
compose' :: P n -> (Return n f r -> r) -> f -> Replace n f r
instance Compose Z a b where
type Return Z a b = a
type Replace Z a b = b
compose' _ f x = f x
instance Compose n f r => Compose (S n) (a -> f) r where
type Return (S n) (a -> f) r = Return n f r
type Replace (S n) (a -> f) r = a -> Replace n f r
compose' x f g = compose' (prev x) f . g
where
prev :: P (S n) -> P n
prev P = P
compose :: Compose (Index n) f r => P n -> (Return (Index n) f r -> r) -> f -> Replace (Index n) f r
compose x = compose' (convert x)
where
convert :: P n -> P (Index n)
convert P = P
-- This does not type check without a signature due to the monomorphism restriction.
compBinRel :: (a -> a -> Bool) -> (a -> a -> Bool)
compBinRel = compose (P::P 2) not
-- This is an example where we compose over higher order functions.
-- Think of it as composing (a -> (b -> c)) and ((b -> c) -> c).
-- This will not typecheck without signatures, despite the fact that it has arguments.
-- However, it will if we use the first solution.
appSnd :: b -> (a -> b -> c) -> a -> c
appSnd x f = compose (P::P 1) ($ x) f
However, this implementation has a few downsides, as annotated in the source.
I attempted (and failed) to use closed type families to infer the composition index automatically. It might have been possible to infer higher order functions like this:
-- Given r and f, where f = x1 -> x2 -> ... -> xN -> r, Infer r f returns N.
type family Infer r f where
Infer r r = Zero
Infer r (a -> f) = Succ (Infer r f)
However, Infer won't work for higher order functions with polymorphic arguments. For example:
ghci> :kind! forall a b. Infer a (b -> a)
forall a b. Infer a (b -> a) :: *
= forall a b. Infer a (b -> a)
GHC can't expand Infer a (b -> a) because it doesn't perform an occurs check when matching closed family instances. GHC won't match the second case of Infer on the off chance that a and b are instantiated such that a unifies with b -> a.
In this code I am trying to have the first parameter in my worker function go be a 'type family' type. I see that in the type type families documentation a similar insert function belongs to the type class, while in my example below it does not.
I am new to type families so maybe I am using them wrong, but what does this error mean?
{-# LANGUAGE TypeFamilies #-}
-- | key
class K a where
-- | iterator for key
type I a :: *
mkI :: a -> I a
--| A map
data (K a) => M a b = M a b
insert :: (K a) => a -> b -> M a b -> M a b
insert = go mkI -- <<< PROBLEM
where
go o a b m = m
Ambiguous type variable `a' in the constraint:
`K a'
arising from an expression type signature at Data/Map2.hs:167:10-33
Probable fix: add a type signature that fixes
these type variable(s)
This compiles:
{-# LANGUAGE TypeFamilies, GADTs, ScopedTypeVariables #-}
-- | key
class K a where
-- | iterator for key
type I a :: *
mkI :: a -> I a
-- | A map
data M x y where
M :: K a => a -> b -> M a b
insert :: forall a b. (K a) => a -> b -> M a b -> M a b
insert = go mkI
where
go :: (a -> I a) -> a -> b -> M a b -> M a b
go o a b m = m
What have I changed and why?
First, I assumed that you wanted the constraint on M, so I used a form of type definition that enforces the constraint and makes it available at use sites, a GADT.
Second, the problem your GHC complained about, the ambiguity. The point is that there's no way for the compiler to deduce which mkI it should use, so we have to tell it. For that, we must bring the type variables used into scope and then tell the compiler in the local signature which type instance to use.
After reading this article on writing polyvariadic functions in Haskell, I tried to write some of my own.
At first I thought I'd try to generalize it - so I could have a function that returned variadic functions by collapsing arguments as given.
{-# OPTIONS -fglasgow-exts #-}
module Collapse where
class Collapse a r | r -> a where
collapse :: (a -> a -> a) -> a -> r
instance Collapse a a where
collapse _ = id
instance (Collapse a r) => Collapse a (a -> r) where
collapse f a a' = collapse f (f a a')
However, the compiler didn't like that:
Collapse.hs:5:9:
Functional dependencies conflict between instance declarations:
instance Collapse a a -- Defined at Collapse.hs:5:9-20
instance (Collapse a r) => Collapse a (a -> r)
-- Defined at Collapse.hs:7:9-43
If I went back and added a wrapper type for the final result, however, it worked:
module Collapse where
class Collapse a r | r -> a where
collapse :: (a -> a -> a) -> a -> r
data C a = C a
instance Collapse a (C a) where
collapse _ = C . id
instance (Collapse a r) => Collapse a (a -> r) where
collapse f a a' = collapse f (f a a')
sum :: (Num a, Collapse a r) => a -> r
sum = collapse (+)
Once I made this change, it compiled fine, and I could use the collapse function in ghci.
ghci> let C s = Collapse.sum 1 2 3 in s
6
I'm not sure why the wrapper type is required for the final result. If anyone could explain that, I'd highly appreciate it. I can see that the compiler's telling me that it's some issue with the functional dependencies, but I don't really grok the proper use of fundeps yet.
Later, I tried to take a different tack, and try and define a variadic function generator for functions that took a list and returned a value. I had to do the same container trick, and also allow UndecidableInstances.
{-# OPTIONS -fglasgow-exts #-}
{-# LANGUAGE UndecidableInstances #-}
module Variadic where
class Variadic a b r | r -> a, r -> b where
variadic :: ([a] -> b) -> r
data V a = V a
instance Variadic a b (V b) where
variadic f = V $ f []
instance (Variadic a b r) => Variadic a b (a -> r) where
variadic f a = variadic (f . (a:))
list :: Variadic a [a] r => r
list = variadic . id
foldl :: (Variadic b a r) => (a -> b -> a) -> a -> r
foldl f a = variadic (Prelude.foldl f a)
Without allowing UndecidableInstances the compiler complained that my instance declarations were illegal:
Variadic.hs:7:0:
Illegal instance declaration for `Variadic a b (V b)'
(the Coverage Condition fails for one of the functional dependencies;
Use -XUndecidableInstances to permit this)
In the instance declaration for `Variadic a b (V b)'
Variadic.hs:9:0:
Illegal instance declaration for `Variadic a b (a -> r)'
(the Coverage Condition fails for one of the functional dependencies;
Use -XUndecidableInstances to permit this)
In the instance declaration for `Variadic a b (a -> r)'
However, once it compiled, I could successfully use it in ghci:
ghci> let V l = Variadic.list 1 2 3 in l
[1,2,3]
ghci> let vall p = Variadic.foldl (\b a -> b && (p a)) True
ghci> :t vall
vall :: (Variadic b Bool r) => (b -> Bool) -> r
ghci> let V b = vall (>0) 1 2 3 in b
True
I guess what I'm looking for is an explanation of why the container type for the final value is necessary, as well as why all the various functional dependencies are necessary.
Also, this seemed odd:
ghci> let vsum = Variadic.foldl (+) 0
<interactive>:1:10:
Ambiguous type variables `a', `r' in the constraint:
`Variadic a a r'
arising from a use of `Variadic.foldl' at <interactive>:1:10-29
Probable fix: add a type signature that fixes these type variable(s)
<interactive>:1:10:
Ambiguous type variable `a'in the constraint:
`Num a' arising from the literal `0' at <interactive>:1:29
Probable fix: add a type signature that fixes these type variable(s)
ghci> let vsum' = Variadic.foldl (+)
ghci> :t vsum'
(Num a, Variadic a a r) => t -> a -> r
ghci> :t vsum' 0
(Num a, Variadic a a r) => a -> r
ghci> let V s = vsum' 0 1 2 3 in s
6
I'm guessing that's fallout from allowing UndecidableInstances, but I don't know, and I'd like to better understand what's going on.
The idea behind functional dependencies is that in a declaration like
class Collapse a r | r -> a where
...
the r -> a bit says that a is uniquely determined by r. So, you can't have instance Collapse (a -> r) (a -> r) and instance Collapse a (a -> r). Note that instance Collapse (a -> r) (a -> r) follows from instance Collapse a a for the complete picture.
In other words, your code is trying to establish instance Collapse t t (the type variable's name is of course unimportant) and instance Collapse a (a -> r). If you substitute (a -> r) for t in the first instance declaration, you get instance Collapse (a -> r) (a -> r). Now this is the only instance of Collapse with the second type parameter equal to (a -> r) that you can have, because the class declaration says that the first type parameter is to be deducible from the second. Yet next you try to establish instance a (a -> r), which would add another instance of Collapse with the second type parameter being (a -> r). Thus, GHC complains.
If you're still experimenting with this, here's an example of constructing a polyvariadic function from a function taking a list, without requiring either a wrapper type or undecidable instances:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
class Variadic a b r | r -> a where
variadic :: ([a] -> b) -> r
instance Variadic a b (a -> b) where
variadic f x = f [x]
instance (Variadic a b (a -> r)) => Variadic a b (a -> a -> r) where
variadic f x y = variadic (f . (x:)) y
vList :: (Variadic a [a] r) => r
vList = variadic id
vFoldl :: (Variadic b a r) => (a -> b -> a) -> a -> r
vFoldl f z = variadic (foldl f z)
vConcat :: (Variadic [a] [a] r) => r
vConcat = vFoldl (++) []
main = do
putStrLn $ vConcat "abc" "def" "ghi" "jkl"
putStrLn $ vList 'x' 'y' 'z'
if vFoldl (&&) True True True True then putStrLn "Yes" else putStrLn "No"
if vFoldl (&&) True True False True then putStrLn "Yes" else putStrLn "No"
The downsides to this approach are that the type checker must be able to infer the type of the result (or you have to annotate it), and that it fails badly on polymorphic numeric constants; the reasons for both problems are discussed in the article you mentioned. Don't know if you'll find that helpful, but I was tinkering with polyvariadic functions earlier and remembered this question.
Michał Marczyk is absolutely correct about the fundeps and instance matching issue, and the wrapper type seems like an easy fix. On the other hand, if you're already reading Oleg's site, you might prefer to go deeper down the rabbit hole and try writing an instance for "any type that isn't a function".
As far as UndecidableInstances goes, the coverage condition is described here; it should be obvious why your instances fail it. Note that the word "undecidable" here means undecidable in roughly the same sense as in "the Halting Problem is undecidable"--that is to say, you're telling GHC to recklessly attempt to resolve code that could send it into an infinite loop based only on your assertion that it's okay. It's fun for hacking neat ideas, but consenting to be a human first-pass type-checker for GHC is a burden I personally find wearying.