Recientemente, comencé a aprender Haskell porque quería ampliar mis conocimientos sobre programación funcional y debo decir que hasta ahora me encanta. El recurso que estoy usando actualmente es el curso 'Haskell Fundamentals Part 1' en Pluralsight. Desafortunadamente, tengo algunas dificultades para entender una cita particular del profesor sobre el siguiente código y esperaba que ustedes pudieran arrojar algo de luz sobre el tema.
Código de acompañamiento
helloWorld :: IO ()
helloWorld = putStrLn "Hello World"
main :: IO ()
main = do
helloWorld
helloWorld
helloWorld
La frase
Si tiene la misma acción IO varias veces en un do-block, se ejecutará varias veces. Entonces, este programa imprime la cadena 'Hola Mundo' tres veces. Este ejemplo ayuda a ilustrar que putStrLn
no es una función con efectos secundarios. Llamamos a la putStrLn
función una vez para definir la helloWorld
variable. Si putStrLn
tuviera un efecto secundario de imprimir la cadena, solo se imprimiría una vez y la helloWorld
variable repetida en el bloque principal no tendría ningún efecto.
En la mayoría de los otros lenguajes de programación, un programa como este imprimiría 'Hello World' solo una vez, ya que la impresión ocurriría cuando putStrLn
se llamara a la función. Esta sutil distinción a menudo hace tropezar a los principiantes, así que piense un poco en esto y asegúrese de comprender por qué este programa imprime 'Hello World' tres veces y por qué lo imprimiría solo una vez si la putStrLn
función imprimiera como un efecto secundario.
Lo que no entiendo
Para mí parece casi natural que la cadena 'Hello World' se imprima tres veces. Percibo la helloWorld
variable (¿o función?) Como una especie de devolución de llamada que se invoca más tarde. Lo que no entiendo es cómo si putStrLn
tuviera un efecto secundario, la cadena se imprimiría solo una vez. O por qué solo se imprimiría una vez en otros lenguajes de programación.
Digamos que en el código C #, supongo que se vería así:
C # (violín)
using System;
public class Program
{
public static void HelloWorld()
{
Console.WriteLine("Hello World");
}
public static void Main()
{
HelloWorld();
HelloWorld();
HelloWorld();
}
}
Estoy seguro de que estoy pasando por alto algo bastante simple o malinterpreto su terminología. Cualquier ayuda sería muy apreciada.
EDITAR:
¡Gracias a todos por sus respuestas o comentarios! Sus respuestas me ayudaron a comprender mejor estos conceptos. No creo que haya hecho clic completamente todavía, pero volveré a visitar el tema en el futuro, ¡gracias!
helloWorld
ser constante, como un campo o variable en C #. No hay ningún parámetro al que se esté aplicandohelloWorld
.putStrLn
no tiene un efecto secundario; simplemente devuelve una acción IO, la misma acción IO para el argumento,"Hello World"
sin importar cuántas veces llameputStrLn
.helloworld
no sería una acción que imprimaHello world
; sería el valor devuelto porputStrLn
después de lo impresoHello World
(a saber,()
).helloWorld = Console.WriteLine("Hello World");
. Simplemente contiene elConsole.WriteLine("Hello World");
en laHelloWorld
función a ejecutar cada vez queHelloWorld
se invoca. Ahora piensa en lo quehelloWorld = putStrLn "Hello World"
hacehelloWorld
. Se asigna a una mónada IO que contiene()
. Una vez que lo vincula>>=
, solo realizará su actividad (imprimiendo algo) y le dará()
en el lado derecho del operador de vinculación.