类型类实例将Int转换为Num a?

时间:2016-06-11 08:06:16

标签: haskell type-inference

我尝试创建一个返回Repa形状的可变函数:

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)

有效:

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

但我必须明确使用3 :: Int而不是3,尽管我的实例明确使用Int。以下让我困惑:

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

我认为实例中的类型签名会强制数字为Int,但它会变成Num a。为什么?如何让编译器识别出所有数字都是Int s?

1 个答案:

答案 0 :(得分:5)

类型类 open :稍后,可能在另一个模块中,您可以定义另一个实例。编译器不能依赖你不这样做,所以它不能提交你到目前为止定义的实例。

您可以为您的函数实例尝试此操作,而不是:

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

Int -> r的实例不同,此实例涵盖整个函数空间a -> r,但需要a ~ Int。这告诉编译器以后不能有任何其他形式的Char -> r或类似的实例,因此允许编译器尽早提交给函数实例。