2010-10-30 12 views
6

Tenga paciencia porque soy muy nuevo en programación funcional y Haskell. Estoy intentando escribir una función en Haskell que toma una lista de enteros, imprime el encabezado de dicha lista y luego devuelve el final de la lista. La función debe ser del tipo [Entero] -> [Entero]. Para dar un poco de contexto, estoy escribiendo un intérprete y se llama a esta función cuando se busca su respectivo comando en una lista asociativa (la clave es el comando, el valor es la función).Haskell: E/S y regreso de una función

Este es el código que he escrito:

dot (x:xs) = do print x 
     return xs 

El compilador da el siguiente mensaje de error:

forth.hs:12:1: 
Couldn't match expected type `[a]' against inferred type `IO [a]' 
    Expected type: ([Char], [a] -> [a]) 
    Inferred type: ([Char], [a] -> IO [a]) 
In the expression: (".", dot) 

sospecho que la llamada a imprimir en la función de puntos es lo que está causando el tipo inferido para ser IO [a]. ¿Hay alguna forma de que pueda ignorar el tipo de impresión de devolución, ya que todo lo que necesito devolver es que la cola de la lista se pase a punto.

Gracias de antemano.

Respuesta

8

En la mayoría de los lenguajes funcionales, esto funcionaría. Sin embargo, Haskell es un puro lenguaje funcional. No se le permite hacer IO en funciones, por lo que la función puede ser

  1. [Int] -> [Int] sin realizar ninguna IO o
  2. [Int] -> IO [Int] con IO

El tipo de dot según se infiere por el compilador es dot :: (Show t) => [t] -> IO [t] pero se puede declarar que sea [Int] -> IO [Int]:

dot :: [Int] -> IO [Int]

Ver mónada IO: http://book.realworldhaskell.org/read/io.html


no he mencionado System.IO.Unsafe.unsafePerformIO que se debe utilizar con mucho cuidado y con un firme entendimiento de sus consecuencias.

+3

El [ 'Debug.Trace'] (http: // www El módulo .haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Debug-Trace.html) también se puede usar para imprimir cosas. –

8

No, su función causa efectos secundarios (también conocido como IO, en este caso, impresión en la pantalla), o no. print hace IO y por lo tanto devuelve algo en IO y esto no se puede deshacer.

Y sería una mala cosa si se pudiera engañar al compilador para que se olvidara del IO. Por ejemplo, si su función [Integer] -> [Integer] es llamada varias veces en su programa con los mismos parámetros (como [] por ejemplo), el compilador podría perfectamente ejecutar la función solo una vez y usar el resultado en todos los lugares donde obtuvo la función " llamado". Su impresión "oculta" solo se ejecutará una vez aunque haya llamado a la función en varios lugares.

Pero el sistema de tipos lo protege y se asegura de que todas las funciones que usan IO, aunque sea de forma indirecta, tengan un tipo IO para reflejar esto. Si desea una función pura, no puede usar print en ella.

5

Como ya sabrá, Haskell es un lenguaje de programación funcional "puro".Por esta razón, los efectos colaterales (como la impresión de un valor en la pantalla) no son incidentales ya que están en más idiomas convencionales. Este hecho le da a Haskell muchas propiedades agradables, pero sería perdonado por no preocuparse por esto cuando todo lo que está haciendo es tratar de imprimir un valor en la pantalla.

Debido a que el lenguaje no tiene una facilidad directa para causar efectos secundarios, la estrategia es que las funciones pueden producir uno o más valores de "acción IO". Una acción IO encapsula algunos efectos secundarios (impresión en la consola, escritura en un archivo, etc.) junto con la posible producción de un valor. Su función dot está produciendo exactamente esa acción. El problema que tiene ahora es que necesita algo que pueda causar el efecto colateral IO, además de desenvolver el valor y posiblemente volver a pasarlo a su programa.

Sin recurrir a hacks, esto significa que debe volver a tener sus acciones IO en la función main. En términos prácticos, esto significa que todo entre main y dot tiene que estar en "IO Monad". Lo que sucede en "IO Monad" se queda en "IO Monad" por así decirlo.

EDITAR

está sobre el ejemplo más simple que podía imaginar por usar su función dot en un programa Haskell válida aquí:

module Main where 

main :: IO() 
main = 
    do 
     let xs = [2,3,4] 
     xr <- dot xs 
     xrr <- dot xr 
     return() 

dot (x:xs) = 
    do 
     print x 
     return xs 
Cuestiones relacionadas