Recentemente, comecei a aprender Haskell porque queria ampliar meu conhecimento em programação funcional e devo dizer que estou realmente amando isso até agora. O recurso que estou usando atualmente é o curso 'Haskell Fundamentals Part 1' sobre Pluralsight. Infelizmente, tenho dificuldade em entender uma citação específica do palestrante sobre o código a seguir e esperava que vocês pudessem lançar alguma luz sobre o tópico.
Código de acompanhamento
helloWorld :: IO ()
helloWorld = putStrLn "Hello World"
main :: IO ()
main = do
helloWorld
helloWorld
helloWorld
A citação
Se você tiver a mesma ação de E / S várias vezes em um bloco bloqueado, ela será executada várias vezes. Portanto, este programa imprime a string 'Hello World' três vezes. Este exemplo ajuda a ilustrar que putStrLnnão é uma função com efeitos colaterais. Chamamos a putStrLnfunção uma vez para definir a helloWorldvariável. Se putStrLntivesse um efeito colateral de imprimir a sequência, ela seria impressa apenas uma vez e a helloWorldvariável repetida no bloco principal não teria nenhum efeito.
Na maioria das outras linguagens de programação, um programa como esse imprime 'Hello World' apenas uma vez, pois a impressão ocorre quando a putStrLnfunção é chamada. Essa distinção sutil costuma atrapalhar os iniciantes, então pense um pouco sobre isso e compreenda por que esse programa imprime 'Hello World' três vezes e por que putStrLno imprimia apenas uma vez se a função fazia a impressão como efeito colateral.
O que eu não entendo
Para mim, parece quase natural que a string 'Hello World' seja impressa três vezes. Eu percebo a helloWorldvariável (ou função?) Como um tipo de retorno de chamada que é chamado mais tarde. O que eu não entendo é como, se putStrLntivesse um efeito colateral, a string seria impressa apenas uma vez. Ou por que seria impresso apenas uma vez em outras linguagens de programação.
Digamos que no código C #, eu presumo que ficaria assim:
C # (violino)
using System;
public class Program
{
public static void HelloWorld()
{
Console.WriteLine("Hello World");
}
public static void Main()
{
HelloWorld();
HelloWorld();
HelloWorld();
}
}
Tenho certeza de que estou ignorando algo bastante simples ou interpretando mal sua terminologia. Qualquer ajuda seria muito apreciada.
EDITAR:
Obrigado a todos por suas respostas! Suas respostas me ajudaram a entender melhor esses conceitos. Acho que ainda não clicou completamente, mas revisarei o tópico no futuro, obrigado!
putStrLn não tem efeito colateral; simplesmente retorna uma ação de E / S, a mesma ação de E / S para o argumento, "Hello World"não importa quantas vezes você chame putStrLn.
helloworldnão seria uma ação que imprime Hello world; seria o valor retornado putStrLn após a impressão Hello World(ou seja, ()).
helloWorld = Console.WriteLine("Hello World");. Você só conter o Console.WriteLine("Hello World");na HelloWorldtoda função a ser executada HelloWorldé invocado. Agora pense sobre o que helloWorld = putStrLn "Hello World"faz helloWorld. Ele é atribuído a uma mônada de E / S que contém (). Depois de vinculado, >>=ele somente executará sua atividade (imprimindo alguma coisa) e fornecerá ()o lado direito do operador de vinculação.
helloWorldser constante, como um campo ou variável em C #. Não há nenhum parâmetro que esteja sendo aplicadohelloWorld.