2011-09-10 106 views
23

Estoy haciendo una función en Haskell que reduce a la mitad los pares en una lista y estoy teniendo un problema. Cuando ejecuto el compilador, se queja de que no se puede realizar la división de un int y que necesito una declaración de tipo int fraccional. He intentado cambiar la declaración de tipo para flotar, pero eso acaba de generar otro error. He incluido el código de la función a continuación y esperaba cualquier forma de ayuda.División en Haskell

halfEvens :: [Int] -> [Int] 
halfEvens [] = [] 
halfEvens (x:xs) | odd x = halfEvens xs 
       | otherwise = x/2:halfEvens xs 

Gracias por leer.

+1

Creo que quieres x 'div' 2 en este caso. Dejaré que otra persona confirme que estoy en lo correcto (no estoy 100% seguro de que lo estoy) y daré una explicación más completa. – MatrixFrog

Respuesta

31

Uso div, que realiza la división de enteros:

halfEvens :: [Int] -> [Int] 
halfEvens [] = [] 
halfEvens (x:xs) | odd x = halfEvens xs 
       | otherwise = x `div` 2 : halfEvens xs 

La función (/) requiere argumentos cuyo tipo es en la clase fraccional, y lleva a cabo la división estándar. La función div requiere argumentos cuyo tipo está en la clase Integral y realiza la división de enteros.

Más precisamente, div y mod round towards negative infinity. Sus primos, quot y rem, se comportan como integer division in C y redondean a cero. div y mod son generalmente correctos cuando se hace una aritmética modular (por ejemplo, al calcular el día de la semana dada una fecha), mientras que quot y rem son un poco más rápidos (creo).

Jugando un poco en GHCi:

> :t div 
div :: Integral a => a -> a -> a 
> :t (/) 
(/) :: Fractional a => a -> a -> a 
> 3/5 
0.6 
> 3 `div` 5 
0 
> (-3) `div` 5 
-1 
> (-3) `quot` 5 
0 
> [x `mod` 3 | x <- [-10..10]] 
[2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1] 
> [x `rem` 3 | x <- [-10..10]] 
[-1,0,-2,-1,0,-2,-1,0,-2,-1,0,1,2,0,1,2,0,1,2,0,1] 
+0

Muchas gracias por su ayuda. – D347th

+0

Sí, quot es más rápido porque eso es lo que la instrucción de la máquina tiende a hacer. Excepto por el procesador NS32k que tenía ambos tipos de instrucciones de división. – augustss

+1

¿Ghc optimiza la división por una potencia de 2 en un desplazamiento a la derecha? Un desplazamiento aritmético a la derecha de n bits se dividirá por 2 ** n, pero se redondeará hacia el infinito negativo (si se desplaza a la derecha a -1, aún se obtiene -1). Para redondear hacia 0, debe agregar (2 ** n) -1 si la entrada es negativa antes de cambiar. En este caso, 'div' debería ser más rápido que' quot' – pat

0

debo añadir que el uso de map simplificaría el código.

HalfIfEven n 
    | even n = n `div` 2 
    | otherwise = n 

halfEvens = map halfIfEven 
+0

Pero eso no le da el mismo resultado. El código original elimina las probabilidades, el tuyo no. Lo más simple sería probablemente 'halfEvens = map (\' div \ '2). filtrar incluso' – semicolon