Di recente, ho iniziato a studiare Haskell perché volevo ampliare le mie conoscenze sulla programmazione funzionale e devo dire che finora lo adoro davvero. La risorsa che sto attualmente utilizzando è il corso "Haskell Fundamentals Part 1" su Pluralsight. Sfortunatamente ho qualche difficoltà a capire una particolare citazione del docente sul seguente codice e spero che voi ragazzi possiate far luce sull'argomento.
Codice di accompagnamento
helloWorld :: IO ()
helloWorld = putStrLn "Hello World"
main :: IO ()
main = do
helloWorld
helloWorld
helloWorld
La citazione
Se hai la stessa azione IO più volte in un do-block, verrà eseguita più volte. Quindi questo programma stampa tre volte la stringa "Hello World". Questo esempio aiuta a dimostrare che putStrLn
non è una funzione con effetti collaterali. Chiamiamo la putStrLn
funzione una volta per definire la helloWorld
variabile. Se putStrLn
avesse avuto un effetto collaterale nel stampare la stringa, sarebbe stata stampata una sola volta e la helloWorld
variabile ripetuta nel do-block principale non avrebbe avuto alcun effetto.
Nella maggior parte degli altri linguaggi di programmazione, un programma come questo stampa 'Hello World' una sola volta, poiché la stampa avverrebbe quando putStrLn
viene chiamata la funzione. Questa sottile distinzione farebbe spesso inciampare i principianti, quindi pensaci un po 'e assicurati di capire perché questo programma stampa "Hello World" tre volte e perché lo stampa solo una volta se la putStrLn
funzione eseguisse la stampa come effetto collaterale.
Quello che non capisco
Per me sembra quasi naturale che la stringa "Hello World" venga stampata tre volte. Percepisco ilhelloWorld
variabile (o la funzione?) Come una sorta di callback che viene invocato in seguito. Quello che non capisco è, come se putStrLn
avesse un effetto collaterale, la stringa verrebbe stampata una sola volta. O perché sarebbe stampato solo una volta in altri linguaggi di programmazione.
Diciamo nel codice C #, presumo che sarebbe simile a questo:
C # (violino)
using System;
public class Program
{
public static void HelloWorld()
{
Console.WriteLine("Hello World");
}
public static void Main()
{
HelloWorld();
HelloWorld();
HelloWorld();
}
}
Sono sicuro di trascurare qualcosa di abbastanza semplice o di interpretare erroneamente la sua terminologia. Qualsiasi aiuto sarebbe molto apprezzato.
MODIFICARE:
Grazie a tutti per le vostre risposte! Le tue risposte mi hanno aiutato a capire meglio questi concetti. Non credo che sia stato ancora completamente cliccato, ma rivisiterò l'argomento in futuro, grazie!
putStrLn
non ha effetti collaterali; restituisce semplicemente un'azione I / O, la stessa azione I / O per l'argomento "Hello World"
non importa quante volte si chiama putStrLn
.
helloworld
non sarebbe un'azione che stampa Hello world
; sarebbe il valore restituito da putStrLn
dopo la stampa Hello World
(ovvero, ()
).
helloWorld = Console.WriteLine("Hello World");
. Basta contenere l' Console.WriteLine("Hello World");
in HelloWorld
ogni funzione da eseguire HelloWorld
viene invocato. Ora pensa a ciò che helloWorld = putStrLn "Hello World"
rende helloWorld
. Viene assegnato a una monade IO che contiene ()
. Una volta che lo vincoli, >>=
solo allora eseguirà la sua attività (stampa qualcosa) e ti darà ()
sul lato destro dell'operatore di rilegatura.
helloWorld
essere costante come un campo o una variabile in C #. Non ci sono parametri a cui applicarehelloWorld
.