Niedawno zacząłem uczyć się Haskell, ponieważ chciałem poszerzyć swoją wiedzę na temat programowania funkcjonalnego i muszę powiedzieć, że bardzo ją kocham. Zasób, którego obecnie używam, to kurs „Podstawy Haskella, część 1” na temat Pluralsight. Niestety mam pewne trudności ze zrozumieniem jednego konkretnego cytatu prowadzącego na temat następującego kodu i miałem nadzieję, że moglibyście rzucić nieco światła na ten temat.
Kod towarzyszący
helloWorld :: IO ()
helloWorld = putStrLn "Hello World"
main :: IO ()
main = do
helloWorld
helloWorld
helloWorld
Cytat
Jeśli masz tę samą akcję We / Wy wiele razy w bloku do, zostanie ona uruchomiona wiele razy. Tak więc ten program trzykrotnie wypisuje napis „Hello World”. Ten przykład pomaga zilustrować, że putStrLn
nie jest to funkcja z efektami ubocznymi. Wywołujemy tę putStrLn
funkcję raz, aby zdefiniować helloWorld
zmienną. Gdyby putStrLn
miał efekt uboczny drukowania łańcucha, wydrukowałby tylko raz, a helloWorld
zmienna powtórzona w głównym bloku do nie miałaby żadnego efektu.
W większości innych języków programowania taki program wypisuje „Hello World” tylko raz, ponieważ drukowanie nastąpiłoby po putStrLn
wywołaniu funkcji. To subtelne rozróżnienie często wprawia w osłupienie początkujących, więc zastanów się nad tym i upewnij się, że rozumiesz, dlaczego ten program drukuje „Hello World” trzy razy i dlaczego wydrukuje go tylko raz, jeśli putStrLn
funkcja wykona drukowanie jako efekt uboczny.
Czego nie rozumiem
Dla mnie wydaje się niemal naturalne, że napis „Hello World” jest drukowany trzy razy. Odbieram helloWorld
zmienną (lub funkcję?) Jako rodzaj wywołania zwrotnego, które jest wywoływane później. Nie rozumiem tylko, jak gdyby putStrLn
miał efekt uboczny, to spowodowałoby, że napis byłby wydrukowany tylko raz. Albo dlaczego zostanie wydrukowany tylko raz w innych językach programowania.
Powiedzmy, że w kodzie C # przypuszczam, że wyglądałoby to tak:
C # (skrzypce)
using System;
public class Program
{
public static void HelloWorld()
{
Console.WriteLine("Hello World");
}
public static void Main()
{
HelloWorld();
HelloWorld();
HelloWorld();
}
}
Jestem pewien, że przeoczam coś dość prostego lub źle interpretuję jego terminologię. Każda pomoc byłaby bardzo mile widziana.
EDYTOWAĆ:
Dziękuję wszystkim za odpowiedzi! Twoje odpowiedzi pomogły mi lepiej zrozumieć te pojęcia. Nie sądzę, aby kliknięcie zostało w pełni kliknięte, ale wrócę do tematu w przyszłości, dziękuję!
putStrLn
nie ma skutków ubocznych; po prostu zwraca akcję IO, tę samą akcję IO dla argumentu "Hello World"
bez względu na to, ile razy wywołujesz putStrLn
.
helloworld
nie byłaby to akcja drukowana Hello world
; to jest wartość zwrócony przez putStrLn
po to drukowana Hello World
(tj ()
).
helloWorld = Console.WriteLine("Hello World");
. Po prostu zawierać Console.WriteLine("Hello World");
w HelloWorld
funkcji mają być wykonane za każdym razem HelloWorld
jest wywoływany. Pomyśl teraz o tym, co helloWorld = putStrLn "Hello World"
czyni helloWorld
. Zostaje przypisany do monady IO, która zawiera ()
. Gdy go połączysz, >>=
dopiero wtedy wykona swoją aktywność (wydrukuje coś) i da ci ()
po prawej stronie operatora powiązania.
helloWorld
stałej wartości, takiej jak pole lub zmienna w języku C #. Nie stosuje się żadnego parametruhelloWorld
.