I have the following code:
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])
It gives me the following errors, and I don't know why.
1) No instance for (Enum [Int]) arising from the arithmetic sequence '0 .. 9'
2) No instance for (Num [Int]) arising from the literal '0'
Does Haskell think that things made with the ".." operator are enumerations? But why isn't there an error for the line that's 4 lines below (with "[1..9]") it then?
Edit: What I want the code to do is like this (procedurally):
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]);
}
Thus, betaFirst(1) == 9, and betaFirst(2) == 90. Yes, somebody may want to suggest a formula for generating this, but I'm going to add a filter of some sort to [0..9], thus reducing the range.
You pass betaRest
to map
. Map is (a -> a) -> [a] -> [a]
so for [Int]
list you pass it it wants an Int -> Int
function. But partially applied betaRest
is [Int] -> Int
.
As for [0..9]
its type is (Enum t, Num t) => [t]
and it's translated into enumFromTo 0 9
application. So compiler figured your error the other way around: if you define special Num
and Enum
instances for lists, so [0..9]
becomes a list of lists of int, then your application will make sense.
But I think you want to use inits
or tails
function. Let us know what you want to achieve so we can help with solution.
A minimal fix to would be to add prevDigits
as an argument to map
and use a lambda abstraction to ignore unused prevDigit
:
| otherwise = sum (map (\prevDigit -> betaRest (n - 1) [0..9]) prevDigits)
(sum (map (betaRest (n - 1)) [0..9]))
Let's reduce the number of parentheses to better be able to see what happens.
sum (map (betaRest (n - 1)) [0..9])
The argument of sum
is
map (betaRest (n-1)) [0 .. 9]
Now, betaRest :: Int -> [Int] -> Int
, hence the type of the partially applied function is
betaRest (n-1) :: [Int] -> Int
hence we can infer the type
map (betaRest (n-1)) :: [[Int]] -> [Int]
But the argument passed to map (betaRest (n-1))
is [0 .. 9]
, which has type
[0 .. 9] :: (Num a, Enum a) => [a]
The Num
constraint comes from the use of an integer literal, and the Enum
constraint from the use of the enumFromTo
function (in its syntax-sugared form [low .. high]
). Passing that as an argument to a function expecting an argument of type [[Int]]
means the type variable a
must be instantiated as [Int]
, and then the constraints need to be checked, i.e. the instances of [Int]
for Num
and Enum
must be looked up. Neither of these exist, hence the error messages.
I'm not sure your procedural example is really what you want,
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;
}
}
the foreach
loop is much easier (and more efficiently) expressed as
sum = prevDigits.length * betaRest(n-1, [0 .. 9]);
so for the foreach
to make sense, there should be a dependence on prevDigit
in the loop body.
The translation to Haskell would be
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
But as stated above, I doubt that's really what you want.