He implementado un binario a decimal función en Haskell y actualmente estoy trabajando en una función a la que convertir un decimal en un valor binario. (Soy consciente de que estas funcionalidades están disponibles en algún lugar aunque no son parte de Preludio.hs)

Se me ocurrió el siguiente código para un C-tipo de lenguaje procedimental, pero tengo problemas para adaptarse en el paradigma funcional.

while (n > 0)
{
    if (n % 2 == 1)
        str = str + "1";
    else
        str = str + "0";
    n = n / 2;
}

Me aventuré en la programación funcional en Haskell sólo recientemente, así que soy bastante nuevo en el funcional de la forma de pensar. He intentado lo anterior, usando tanto la recursividad y la comprensión de listas, pero no estoy seguro sobre cómo colocar los guardias y la lógica correctamente ya que esto implica varias condiciones. Yo uso un Int lista para celebrar el binario independiente bits.

--Decimal to binary
toBin:: Int -> [Int]
toBin 0 = [0]
toBin n | (n % 2 == 1) =
        |(n % 2 == 0) = 

He entendido que el modelo anterior iba a dejar que el programa elija cualquiera de los de la guardia y de fin de evaluar la función. Estoy en el camino equivocado aquí?

A continuación es lo que me ocurrió con primitivas de la recursión para convertir cualquier base (menos de 10, en lugar de la 2) decimales.

toDecimal :: [Int] -> Int
toDecimal [] = 0
toDecimal (x:xs) = (x * 2 ^(length xs)) + bin xs

Gracias de antemano.

InformationsquelleAutor Tru | 2012-02-06

4 Comentarios

  1. 15

    No hay % operador; usted está probablemente en busca de `mod` lugar:

    toBin 0 = [0]
    toBin n | n `mod` 2 == 1 = ...
            | n `mod` 2 == 0 = ...

    Guardias permiten elegir entre varias ramas de una función. En este caso, cada ... será el resultado de toBin n si su correspondiente condición es verdadera. Para anexar dos listas, puede utilizar el ++ operador, y `div` corresponde a la división entera:

    toBin 0 = [0]
    toBin n | n `mod` 2 == 1 = toBin (n `div` 2) ++ [1]
            | n `mod` 2 == 0 = toBin (n `div` 2) ++ [0]

    Sin embargo, esto tiene un par de problemas. Para empezar, se inicia siempre con el resultado 0, que es redundante; además, el uso de ++ [1] es lento, ya que tiene que ir a través de toda la lista para añadir un elemento a la final; sería mejor anteponer cada elemento como vamos, y luego inversa el resultado al final.

    Para solucionar ambas cosas, vamos a dividir toBin en una función principal y una función auxiliar:

    toBin 0 = [0]
    toBin n = reverse (helper n)
    
    helper 0 = []
    helper n | n `mod` 2 == 1 = 1 : helper (n `div` 2)
             | n `mod` 2 == 0 = 0 : helper (n `div` 2)

    En esta versión, utilizamos la : operador, que tiene un valor y una lista, y devuelve la lista con el valor antepone el principio. También nos devuelva un resultado vacío de 0 en nuestro ayudador, y manejar el 0 en caso toBin lugar, así que no hay más 0s de lo necesario en el resultado.

    Podemos simplificar helper‘s código sin pasar por los guardias del todo, ya que acaba de escribir el resultado de n `mod` 2 de nuevo en el lado derecho:

    helper 0 = []
    helper n = (n `mod` 2) : helper (n `div` 2)

    Por último, hay una función que hace un div y un mod en una sola, que puede ser más eficiente:

    helper 0 = []
    helper n = let (q,r) = n `divMod` 2 in r : helper q

    Como una nota adicional, esto en realidad no convertir de decimal a binario, se convierte un entero a binario; Haskell implementaciones es raro para almacenar números enteros en formato decimal, a pesar de que son escritos e impresos en ese formato. Para escribir una completa conversión de decimal a binario, una función que analiza un decimal cadena en un entero sería necesario.

    • «una función que analiza un decimal cadena en un entero sería necesario» – como, erm, read?
    • Sí, pero es de suponer que el OP está tratando de implementar esta desde cero 🙂 Después de todo, showIntAtBase también existe.
  2. 5
    toBinary :: Int -> [ Int ]
    
    toBinary 0 = [ 0 ]
    
    toBinary n = toBinary ( n `quot` 2 ) ++ [ n `rem` 2 ]
  3. 2
    toBin :: Int -> [Int]
    toBin 0 = [0]
    toBin 1 = [1]
    toBin n
        | n `mod` 2 == 0 = toBin (n `div` 2) ++ [0]
        | otherwise = toBin (n `div` 2) ++ [1]

    0 y 1 son los casos triviales.
    si n es incluso entonces usted debe anexar cero hasta el final, de lo contrario anexar uno.
    Es una buena práctica para la captura de todo en su última guardia de expresión (que es la razón por la que he utilizado de otra manera que de la misma como Verdadera)

  4. 0

    Puede utilizar el unfoldr función de la Data.List módulo y intToDigit de Data.Char:

    dec2bin :: Int -> [Char]
    dec2bin = reverse . map intToDigit . unfoldr (\x -> if x==0 then Nothing else Just(rem x 2, div x 2))

    Lo que pasa aquí es que el unfoldr función procesos la entrada con el cable de función anónima hasta que se devuelve Nothing, mientras que la agregación de el primer valor de Just en una lista. Esta lista contiene Ints, por lo que necesitan ser convertidos a Chars usando intToDigit invierte, ya que son recogidos en un orden inverso. Una lista de Chars es una cadena en Haskell, así que estás hecho.

Dejar respuesta

Please enter your comment!
Please enter your name here