【问题标题】:Haskell Error: "No instance for (Enum [Int])Haskell 错误:“(枚举 [Int])没有实例
【发布时间】:2012-10-02 06:00:04
【问题描述】:

我有以下代码:

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) (Enum [Int]) 没有来自算术序列'0 .. 9'的实例

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],从而缩小范围。

【问题讨论】:

  • 并非所有错误都在一次运行中出现 - 某些错误可能不会显示,因为编译器因其他错误而停止。是的,.. 一个枚举,只是你不这么认为。另外,为什么betaFirst 只接受一个参数然后应用于两个?它应该做什么?
  • @thomas-m-dubuisson 啊,原来是枚举。我想那时可以使用范围函数。仔细看,betaFirst 没有调用自己,它调用了betaRest
  • 尝试将[0..9] 更改为[(0 :: Int)..9]。它应该会给你一个更好的错误信息。
  • 问题可能出在betaRests 否则分支。有一些放错位置的括号和另一个与列表嵌套有关的问题。
  • @JohnL 哪些括号放错了?在我看来,它们都很好;我把它们放在betaRest (n - 1) 周围,这样我就可以将 map 与带有多个参数的函数一起使用。

标签: haskell compiler-errors


【解决方案1】:

您将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)

【讨论】:

  • 啊,好吧,我明白为什么它现在失败了,以及为什么给出的错误没有帮助/无关。我是新手,所以我不知道initstails 是什么,但是在查找它们之后,我也不是我想要的。我已经在主要问题中添加了我想要做的事情。
【解决方案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] 的实例@987654339 @ 和 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 有意义,循环体中应该有对prevDigit 的依赖。

翻译成 Haskell 是

betaRest n prevDigits
    | n == 0    = length prevDigits
    | otherwise = length prevDigits * betaRest (n-1) [0 .. 9]
    -- or with the loop, with the small improvement that `betaRest (n-1) [0 .. 9]
    -- is only computed once (if the Haskell implementation is sensible)
    -- | otherwise = sum $ map (const $ betaRest (n-1) [0 .. 9]) prevDigits

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

【讨论】:

  • 不,这不是我想要的,但由于该功能令人困惑,我什至在程序上都遇到了麻烦。不过还是谢谢!
  • 你能在更高的层次上描述你想让这个函数做什么吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多