8
votes

I couldn't find an answer to my question among several ambiguous type variable error questions.

Basically I want to take type information to the value level. The last line in this example fails.

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeOperators #-}

module Test where

data Typ = TInteger | TString deriving Show

data Empty = Empty
data a ## b = Cons a b

class Typical a b | a -> b where
    typical :: a -> b

instance Typical Empty [Typ] where
    typical _ = []

instance Typical Integer Typ where
    typical _ = TInteger

instance Typical String Typ where
    typical _ = TString

instance (Typical a Typ, Typical b [Typ]) => Typical (a ## b) [Typ] where
    typical _ = typical (undefined :: a) : typical (undefined :: b)

Here is the first error message:

Test.hs:27:17:
Could not deduce (Typical a0 Typ) arising from a use of `typical'
from the context (Typical a Typ, Typical b [Typ])
  bound by the instance declaration at Test.hs:26:10-67
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
  instance Typical String Typ -- Defined at Test.hs:23:10
  instance Typical Integer Typ -- Defined at Test.hs:20:10
Possible fix: add an instance declaration for (Typical a0 Typ)
In the first argument of `(:)', namely `typical (undefined :: a)'
In the expression:
  typical (undefined :: a) : typical (undefined :: b)
In an equation for `typical':
    typical _ = typical (undefined :: a) : typical (undefined :: b)

I just don't get it.

What is a0 here? Could it be that the a from my last line is not identified with that from the 2nd last line?

Where should I put a type signature and why?

Please enlighten me!

1
Adding a functional dependency states that one type is uniquely determined by another. I believe you need to either remove one of the instances of Typical a Typ or create specific instances for each possible variation of your combined instance.Mokosha
@Mokosha: The functional dependency is a -> b, not b -> a, so I don't think instances must be removed. I don't think I got the second part of your last sentence.Jo So

1 Answers

5
votes

Ok, I have a solution, but I don't know if this is the cleanest workaround.

Adding {-# LANGUAGE ScopedTypeVariables #-} makes the code compile. This makes it possible to identify a0 with a from the error message (corresponding to the as from the last two lines of the code).

Please comment!