In the code below, ghc complains about ambiguity. I'm assuming it's because type classes are open (outside code could define new instance and actually make this ambiguous).
If I could somehow close the Indexable
type class, would that be enough to make this idea a valid way to implement basic associated types?
The question is more about theoretical aspects of type inference than about how to get it to work in Haskell. Is the problem here a theoretical issue with such a system that would make inference not possible for t1
below? Would allowing closed type classes be enough to infer t1
unambiguously?
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
class Indexable a where
instance Indexable (String, Int, Char) where
instance Indexable ([(String, a)], String, a) where
test1 :: Indexable (a,b,c) => a -> b -> c
test1 x y = undefined
t1 = test1 "hi" 3 == 'c'
main = return ()
----------------------------------------------------------------
-- indexable.hs:14:6: --
-- No instance for (Indexable ([Char], b0, Char)) --
-- arising from a use of ‘test1’ --
-- The type variable ‘b0’ is ambiguous --
-- Note: there is a potential instance available: --
-- instance Indexable (String, Int, Char) --
-- -- Defined at indexable.hs:8:10 --
-- In the first argument of ‘(==)’, namely ‘test1 "hi" 3’ --
-- In the expression: test1 "hi" 3 == 'c' --
-- In an equation for ‘t1’: t1 = test1 "hi" 3 == 'c' --
-- --
-- indexable.hs:14:17: --
-- No instance for (Num b0) arising from the literal ‘3’ --
-- The type variable ‘b0’ is ambiguous --
-- Note: there are several potential instances: --
-- instance Num Double -- Defined in ‘GHC.Float’ --
-- instance Num Float -- Defined in ‘GHC.Float’ --
-- instance Integral a => Num (GHC.Real.Ratio a) --
-- -- Defined in ‘GHC.Real’ --
-- ...plus three others --
-- In the second argument of ‘test1’, namely ‘3’ --
-- In the first argument of ‘(==)’, namely ‘test1 "hi" 3’ --
-- In the expression: test1 "hi" 3 == 'c' --
----------------------------------------------------------------
Num
instance and thatIndexable
is closed and the only possible keys areInt
andString
isn't enough to know that the key must beInt
. You would also need to know that there will never be aNum
instance forString
, implying thatNum
is also closed. Alternatively, you could tell that you must be using the instance where the container is aString
from the fact that the container isn't a[(String, a)]
and knowingIndexable
is closed. Choosing the instance based on the container is exactly what you'd do with fundeps or type families. - Cirdec