首页 文章

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

提问于
浏览
2

我有以下代码:

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)没有来自文字'0'的(Num [Int])实例

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 回答

  • 2

    您将 betaRest 传递给 map . 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)
    
  • 4
    (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] 的实例 NumEnum . 这些都不存在,因此出现错误消息 .

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

    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
    

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

相关问题