Igual (=) Vs flecha izquierda (<-) símbolos en haskell

Código de trabajo:

import System main = do [file1, file2] <- getArgs --copy file contents str <- readFile file1 writeFile file2 str 

Código de locking:

 import System main = do [file1, file2] = getArgs str = readFile file1 writeFile file2 str 

Cuando lo intenté, arrojó un error como:

a.hs: 6: 18: error de análisis en la entrada ‘=’

Entonces, ¿cuán diferente es <- from = ?

Para entender la diferencia real, debes comprender las mónadas y el deslumbramiento descrito por @rightfold en su respuesta.

Para el caso específico de la mónada IO, como en el ejemplo de getArgs , se puede hacer una intuición aproximada pero útil de la siguiente manera:

  • x <- action ejecuta la action IO, obtiene su resultado y lo vincula a x
  • let x = action define x para ser equivalente a la action , pero no ejecuta nada. Más adelante, puede usar y <- x significa y <- action .

Los progtwigdores que provienen de lenguajes imperativos que permiten cierres, pueden extraer esta comparación paralela aproximada con Javascript:

 var action = function() { print(3); return 5; } // roughly equivalent to x <- action print('test 1') var x = action() // output:3 // x is 5 // roughly equivalent to let y = action print('test 2') var y = action // output: nothing // y is a function // roughly equivalent to z <- y print('test 3') var z = y() // output:3 // z is 5 

De nuevo: esta comparación se centra solo en IO. Para otras mónadas, debes verificar qué >>= realmente es, y pensar en el deslumbramiento de do .

 do x <- y fx 

es equivalente a:

 y >>= \x -> fx 

 do let x = y fx 

es equivalente a

 fy 

es decir, let / = does no une monadic mientras que <- does.

El código no se comstack porque los tipos no coinciden. Carguemos una sesión GHCI y observemos los tipos de funciones que está usando –

 > :t writeFile writeFile :: FilePath -> String -> IO () > > :t readFile readFile :: FilePath -> IO String 

Así que writeFile quiere un FilePath y una String . Desea obtener la String de readFile , pero readFile devuelve IO String lugar de String .

Haskell es un lenguaje muy basado en principios. Tiene una distinción entre funciones puras (que dan los mismos resultados cada vez que se las llama con los mismos argumentos) y código impuro (que puede dar resultados diferentes, por ejemplo, si la función depende de alguna entrada del usuario). Las funciones que se ocupan de entrada / salida (IO) siempre tienen un tipo de retorno que está marcado con IO . El sistema de tipos garantiza que no se puede usar un código IO impuro dentro de funciones puras; por ejemplo, en lugar de devolver una String la función readFile devuelve una IO String .

Aquí es donde la notación <- es importante. Le permite acceder al String dentro del IO y garantiza que, haga lo que haga con esa cadena, la función que está definiendo siempre se marcará con IO . Compare lo siguiente -

 > let x = readFile "tmp.txt" > :tx x :: IO String 

que no es lo que queremos, a esto

 > y <- readFile "tmp.txt" > :ty y :: String 

que es lo que queremos Si alguna vez tiene una función que devuelve un IO a y desea acceder al a , necesita usar <- para asignar el resultado a un nombre. Si su función no devuelve IO a , o si no desea obtener el a dentro de IO , puede usar = .

 let x = readFile file1 

Esto toma la acción ” readFile file1 ” y almacena la acción en x .

 x <- readFile file1 

Esto ejecuta la acción " readFile file1 " y almacena el resultado de la acción en x .

En el primer ejemplo, x es un objeto de acción de E / S no ejecutado. En el segundo ejemplo, x es el contenido de un archivo en el disco.