programas - problemas con conversiones de números triviales en Haskell
programas hechos en haskell (2)
Estoy intentando escribir una función trivial para soltar el último dígito de un número y devolver el resto del número.
dropLastDigit :: (Integral b) => b -> b
dropLastDigit x = (quot x 10) * (floor $ logBase 10 x)
sin embargo, cuando intento cargar esto en ghci, obtengo:
Could not deduce (Floating b) arising from a use of ‘logBase’
from the context (Integral b)
bound by the type signature for
dropLastDigit :: Integral b => b -> b
at haskelljokes.hs:6:18-39
Possible fix:
add (Floating b) to the context of
the type signature for dropLastDigit :: Integral b => b -> b
In the second argument of ‘($)’, namely ‘logBase 10 x’
In the expression: floor $ logBase 10 x
In an equation for ‘dropLastDigit’:
dropLastDigit x = floor $ logBase 10 x
Sin embargo, ejecutar este código en ghci:
:t (quot 101 10) * (floor $ logBase 10 101)
produce: (quot 101 10) * (floor $ logBase 10 101) :: Integral a => a
Mi pregunta es, ¿qué estoy haciendo mal? ¿Y por qué (el código idéntico?) Trabaja en ghci?
Cambia tu función a
dropLastDigit :: (Integral b) => b -> b
dropLastDigit x = (quot x 10) * (floor $ logBase 10 (fromIntegral x))
El código que estás ejecutando en GHCi no es idéntico. Usted ha reemplazado x por 101 . La x en su función fue anotada (por tipo de firma) para ser de tipo b para cualquier tipo b en la clase Integral , pero logBase necesita algo en la clase Floating .
Por otro lado, el literal 101 es de tipo Num a => a , es decir, está sobrecargado y se puede usar en cualquier tipo numérico. Entonces GHCi puede usarlo en tipo Integer en la primera aparición, como un argumento de quot , y como un Double en la segunda ocurrencia, como un argumento para logBase .
No es idéntico. Puedes verificar esto fácilmente:
ghci> let value101 = 101 :: Integral b => b
ghci> let value10 = 10 :: Integral b => b
ghci> (quot value101 value10) * (floor $ logBase value10 value101)
<interactive>:7:28:
Could not deduce (RealFrac s0) arising from a use of `floor''
from the context (Integral a)
bound by the inferred type of it :: Integral a => a
at <interactive>:7:1-60
The type variable `s0'' is ambiguous
Note: there are several potential instances:
instance RealFrac Double -- Defined in `GHC.Float''
instance RealFrac Float -- Defined in `GHC.Float''
instance Integral a => RealFrac (GHC.Real.Ratio a)
-- Defined in `GHC.Real''
In the expression: floor
In the second argument of `(*)'', namely
`(floor $ logBase value10 value101)''
In the expression:
(quot value101 value10) * (floor $ logBase value10 value101)
-- even more...
El problema es que tanto 10 como 101 tienen el tipo Num a => a , independientemente de dónde los use. Así que logBase 10 101 usó con la instancia Fractional predeterminada ( Double ), mientras que quot usó con la instancia Integral predeterminada.
Dicho esto, su función no "suelta" el último dígito. Si solo quiere transformar 12345 a 1234 , puede simplificar dropLastDigit para
dropLastDigit x = x `div` 10
Si, sin embargo, desea transformar 12345 a 12340 , solo tiene que multiplicar por diez después:
dropLastDigit x = 10 * (x `div` 10)