rityzmon
rityzmon

Reputation: 1965

Typeclass instance turned Int into Num a?

I tried to create a variadic function that returns a Repa shape:

class Indexable r where
  idx :: [Int] -> r

instance Indexable Int where
  idx [x] = x

instance (Indexable b) => Indexable (Int :. b) where
  idx (x:xx) = x :. (idx xx)

instance (Indexable a) => Indexable (Z :. a) where
  idx xs = Z :. (idx xs)

instance (Indexable r) => Indexable (Int -> r) where
  idx xs = \x -> idx (x:xs)

It works:

> fromListUnboxed (idx [] (3 :: Int)) [1..3] :: Array U DIM1 Int
AUnboxed (Z :. 3) [1,2,3]

but I have to explicitly use 3 :: Int instead of just 3, despite my instances explicitly using Int. The following then confused me:

> :t idx [] 3
idx [] 3 :: (Num a, Indexable (a -> t)) => t

I thought the type signatures in the instances would force the number to be an Int, but it turned into a Num a. Why? And how do I get the compiler to recognize that all the numbers are going to be Ints?

Upvotes: 1

Views: 45

Answers (1)

chi
chi

Reputation: 116174

Type classes are open: later on, possibly in another module, you could define another instance. The compiler can't rely on you not doing that, so it can not commit to the instances you have defined so far.

You could try this for your function instance, instead:

instance (Indexable r, a ~ Int) => Indexable (a -> r) where
  idx xs = \x -> idx (x:xs)

Unlike the instance for Int -> r, this instance covers the whole function space a -> r, but requires that a ~ Int. This tells the compiler that there can not be any other instance of the form Char -> r or similar later on, so the compiler is allowed to commit early to the function instance.

Upvotes: 5

Related Questions