Haskell错误:“没有实例(Enum [Int])

时间:2012-10-02 06:00:05

标签: haskell compiler-errors

我有以下代码:

betaRest :: Int -> [Int] -> Int
betaRest n prevDigits | n == 0    = (length prevDigits)
                      | otherwise = (sum (map (betaRest (n - 1)) [0..9]))

betaFirst :: Int -> Int
betaFirst n | n == 0    = 0
            | otherwise = (betaRest (n - 1) [1..9])

它给了我以下错误,我不知道为什么。

  

1)算术序列'0 .. 9'

中没有(Enum [Int])的实例      

2)没有(Num [Int])的实例来自文字'0'

Haskell是否认为使用“..”运算符创建的内容是枚举?但是为什么下面的4行(用“[1..9]”)的行不存在错误呢?


编辑:我想要的代码是这样的(程序性的):

int betaRest(int n, int[] prevDigits) {
  if (n == 0) return prevDigits.length;
  else {
    sum = 0;
    foreach prevDigit in prevDigits {
      sum += betaRest(n - 1, [0..9]);
    }
    return sum;
  }
}

int betaFirst(int n) {
  if (n == 0) return 0;
  else return betaRest(n - 1, [1..9]);
}

因此,betaFirst(1)== 9,betaFirst(2)== 90.是的,有人可能想建议生成这个的公式,但是我要添加某种过滤器到[0 ..9],从而缩小了范围。

2 个答案:

答案 0 :(得分:4)

您将betaRest传递给map。地图为(a -> a) -> [a] -> [a],因此对于[Int]列表,您传递它需要Int -> Int函数。但部分应用的betaRest[Int] -> Int

对于[0..9],其类型为(Enum t, Num t) => [t],并将其翻译为enumFromTo 0 9个应用程序。所以编译器反过来想出了你的错误:如果为列表定义特殊的NumEnum实例,那么[0..9]就会成为int列表的列表,那么你的应用程序就有意义了。

但我认为你想使用initstails功能。让我们知道您想要实现的目标,以便我们为解决方案提供帮助。

最小的修复方法是将prevDigits作为参数添加到map并使用lambda抽象来忽略未使用的prevDigit

   | otherwise = sum (map (\prevDigit -> betaRest (n - 1) [0..9]) prevDigits)

答案 1 :(得分:2)

(sum (map (betaRest (n - 1)) [0..9]))

让我们减少括号的数量,以便更好地了解会发生什么。

sum (map (betaRest (n - 1)) [0..9])

sum的论点是

map (betaRest (n-1)) [0 .. 9]

现在,betaRest :: Int -> [Int] -> Int,因此部分应用的函数的类型是

betaRest (n-1) :: [Int] -> Int

因此我们可以推断出类型

map (betaRest (n-1)) :: [[Int]] -> [Int]

但传递给map (betaRest (n-1))的论点是[0 .. 9],其类型为

[0 .. 9] :: (Num a, Enum a) => [a]

Num约束来自使用整数文字,Enum约束来自enumFromTo函数的使用(以其语法加糖形式[low .. high] )。将其作为参数传递给期望类型为[[Int]]的参数的函数意味着必须将类型变量a实例化为[Int],然后需要检查约束,即实例必须查找[Int]Num的{​​{1}}。这些都不存在,因此出现错误消息。

我不确定你的程序示例是否真的是你想要的,

Enum

int betaRest(int n, int[] prevDigits) { if (n == 0) return prevDigits.length; else { sum = 0; foreach prevDigit in prevDigits { sum += betaRest(n - 1, [0..9]); } return sum; } } 循环更容易(并且更有效)表示为

foreach

因此,sum = prevDigits.length * betaRest(n-1, [0 .. 9]); 有意义,循环体中应该依赖foreach

Haskell的翻译将是

prevDigit

但如上所述,我怀疑这真的是你想要的。