opciones - Error Haskell: "No hay instancia para(Enum[Int])
or en haskell (2)
Tengo el siguiente código:
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])
Me da los siguientes errores y no sé por qué.
1) No hay instancia para (Enum [Int]) que surja de la secuencia aritmética ''0 .. 9''
2) No hay instancia para (Num [Int]) que surja del literal ''0''
¿Haskell piensa que las cosas hechas con el operador ".." son enumeraciones? Pero ¿por qué no hay un error para la línea que está 4 líneas abajo (con "[1..9]") entonces?
Editar: Lo que quiero que el código haga es así (proceduralmente):
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]);
}
Por lo tanto, betaPrimer (1) == 9 y betaPrimer (2) == 90. Sí, alguien puede querer sugerir una fórmula para generar esto, pero voy a agregar un filtro de algún tipo a [0..9 ], reduciendo así el rango.
betaRest
para map
. El mapa es (a -> a) -> [a] -> [a]
así que para la lista [Int]
que lo pasa quiere una función Int -> Int
. Pero betaRest
aplicado parcialmente es [Int] -> Int
.
En cuanto a [0..9]
su tipo es (Enum t, Num t) => [t]
y se traduce en la aplicación enumFromTo 0 9
. Así que el compilador calculó su error al revés: si define instancias Num
y Enum
especiales para listas, entonces [0..9]
convierte en una lista de listas de int, entonces su aplicación tendrá sentido.
Pero creo que quieres usar la función inits
o tails
. Háganos saber lo que quiere lograr para que podamos ayudar con la solución.
Una solución mínima sería agregar prevDigits
como argumento para map
y usar una abstracción lambda para ignorar prevDigit
no prevDigit
:
| otherwise = sum (map (/prevDigit -> betaRest (n - 1) [0..9]) prevDigits)
(sum (map (betaRest (n - 1)) [0..9]))
Reduzcamos el número de paréntesis para poder ver mejor qué sucede.
sum (map (betaRest (n - 1)) [0..9])
El argumento de la sum
es
map (betaRest (n-1)) [0 .. 9]
Ahora, betaRest :: Int -> [Int] -> Int
, de ahí que el tipo de la función parcialmente aplicada es
betaRest (n-1) :: [Int] -> Int
por lo tanto, podemos inferir el tipo
map (betaRest (n-1)) :: [[Int]] -> [Int]
Pero el argumento pasado al map (betaRest (n-1))
es [0 .. 9]
, que tiene
[0 .. 9] :: (Num a, Enum a) => [a]
La restricción Num
proviene del uso de un literal entero, y la restricción Enum
del uso de la función enumFromTo
(en su forma azucarada de sintaxis [low .. high]
). Pasar eso como un argumento a una función esperando un argumento de tipo [[Int]]
significa que la variable de tipo a
debe ser instanciada como [Int]
, y luego las restricciones deben ser verificadas, es decir, las instancias de [Int]
para Num
y Enum
debe ser buscado. Ninguno de estos existe, de ahí los mensajes de error.
No estoy seguro de que tu ejemplo de procedimiento sea realmente lo que quieres,
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;
}
}
el ciclo foreach
es mucho más fácil (y más eficiente) expresado como
sum = prevDigits.length * betaRest(n-1, [0 .. 9]);
prevDigit
para que el foreach
tenga sentido, debería haber una dependencia de prevDigit
en el cuerpo del bucle.
La traducción a Haskell sería
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
Pero como se dijo anteriormente, dudo que sea realmente lo que quieres.