Reputation: 1965
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 Int
s?
Upvotes: 1
Views: 45
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