3

我有以下代码:

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 中添加某种过滤器],从而缩小范围。

4

2 回答 2

4

betaRest传给map. 地图对于您传递它(a -> a) -> [a] -> [a]的列表来说是这样的,它需要一个功能。但部分应用的是.[Int]Int -> IntbetaRest[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)
于 2012-10-02T07:01:48.003 回答
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))is [0 .. 9],它有类型

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

Num约束来自整数文字的使用,而约束Enum来自enumFromTo函数的使用(以其语法糖化形式[low .. high])。将其作为参数传递给需要类型参数的函数[[Int]]意味着类型变量a必须实例化为[Int],然后需要检查约束,即必须查找[Int]forNum和的实例。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

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

于 2012-10-02T12:04:54.633 回答