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)