构造数组时键入错误

时间:2014-09-09 15:38:55

标签: haskell types

我正在尝试用数组记住这个函数:

a n 0 = n
a n k = a (2*n - 1) (k - 1) / a (2*n) (k - 1)

我做到了这一点:

import Data.Array

cache :: (Ix a, Real b) => Array a [(a, b)]
cache = array bounds [(i, func i) | i <- range bounds]
    where bounds = ((0,0), (1000, 1000))
          func elem =
            let f n 0 = n
                f n k = f (2*n - 1) (k - 1) / f (2*n) (k - 1)
             in uncurry f elem

a n k = cache!(n,k)

GHCi因此错误而失败:

aarr.hs:6:16:
    Could not deduce (a ~ ([(a, b)], b0))
    from the context (Ix a, Real b)
      bound by the type signature for
                 values :: (Ix a, Real b) => Array a [(a, b)]
      at aarr.hs:5:11-44
      ‘a’ is a rigid type variable bound by
          the type signature for values :: (Ix a, Real b) => Array a [(a, b)]
          at aarr.hs:5:11
    Expected type: (a, a)
      Actual type: (([(a, b)], b0), ([(a, b)], b0))
    Relevant bindings include
      bounds :: (([(a, b)], b0), ([(a, b)], b0)) (bound at aarr.hs:7:11)
      values :: Array a [(a, b)] (bound at aarr.hs:6:1)
    In the first argument of ‘array’, namely ‘bounds’
    In the expression: array bounds [(i, func i) | i <- range bounds]

我头脑中的所有类型错误(以及无限类型错误)都在旋转......我认为这可行。

1 个答案:

答案 0 :(得分:3)

问题

您的cache功能存在两个问题,导致无法编译。

第一个是(/)的类型如下,

(/) :: Fractional a => a -> a -> a

然而,编译器会将bounds中的值推断为Integral类型,这与使用/时不相符。

第二个是您的类型签名不正确。

解决方案

有很多方法可以解决这个问题,但最简单的可能是以下几点,

cache :: (Ix b, Fractional b) => Array (b, b) b
cache = array bounds [(i, func i) | i <- range bounds]
    where bounds = ((0.0,0.0), (1000.0, 1000.0))
          func elem =
            let f n 0 = n
                f n k = f (2*n - 1) (k - 1) / f (2*n) (k - 1)
             in uncurry f elem

请注意,bounds的值现在是Fractional值。

另请注意,我更改了您的类型签名。 Array的第一个类型参数必须是Ix实例。由于您使用Fractional对作为索引,因此需要在类型中反映出来。其次,这也意味着数组中元素的值与索引共享相同的类型。如果您希望索引为积分值,则可以执行以下操作,

cache :: (Integral a, Ix a, Fractional b) => Array (a, a) b
cache = array bounds [(i, func i) | i <- range bounds]
    where bounds = ((0,0), (1000, 1000))
          func (a, b) =
            let f n 0 = n
                f n k = f (2*n - 1) (k - 1) / f (2*n) (k - 1)
             in uncurry f (fromIntegral a, fromIntegral b)

注意,我不知道是否使用Integral类型与Fractional类型,因为索引有任何性能方面的考虑,因为我不经常使用Array类型