Нещодавно я почав вивчати Haskell, тому що хотів розширити свої знання з функціонального програмування, і мушу сказати, що дуже люблю його до цих пір. Зараз я використовую курс "Основи Haskell, частина 1" з питань плюралізму. На жаль, у мене є труднощі з розумінням однієї конкретної цитати лектора про наступний код і сподівався, що ви, хлопці, зможете пролити трохи світла на цю тему.
Супровідний кодекс
helloWorld :: IO ()
helloWorld = putStrLn "Hello World"
main :: IO ()
main = do
helloWorld
helloWorld
helloWorld
Цитата
Якщо у вас є одна і та ж дія IO кілька разів у do-блоці, вона буде виконуватися кілька разів. Тож ця програма виводить рядок "Hello World" тричі. Цей приклад допомагає проілюструвати, що putStrLnце не функція з побічними ефектами. Ми викликаємо putStrLnфункцію один раз для визначення helloWorldзмінної. Якби putStrLnбув побічний ефект друку рядка, він надрукував би лише один раз, і helloWorldзмінна, повторена в основному блоці виконання, не мала би жодного ефекту.
У більшості інших мов програмування така програма буде надрукувати "Hello World" лише один раз, оскільки друк відбудеться під час putStrLnвиклику функції. Ця тонка відмінність часто відштовхує початківців, тому подумайте над цим трохи і переконайтеся, що ви розумієте, чому ця програма друкує "Hello World" тричі і чому вона надрукує її лише один раз, якщо putStrLnфункція зробила друк як побічний ефект.
Що я не розумію
Мені здається майже природним, що рядок "Hello World" друкується тричі. Я сприймаю helloWorldзмінну (або функцію?) Як своєрідний зворотний виклик, який викликається пізніше. Чого я не розумію, це те, як якщо putStrLnпобічний ефект матиме наслідком, що рядок надрукується лише один раз. Або чому він буде надрукований лише один раз іншими мовами програмування.
Скажімо, у C # коді, я вважаю, що це виглядатиме так:
C # (скрипка)
using System;
public class Program
{
public static void HelloWorld()
{
Console.WriteLine("Hello World");
}
public static void Main()
{
HelloWorld();
HelloWorld();
HelloWorld();
}
}
Я впевнений, що я пропускаю щось зовсім просте або неправильно трактую його термінологію. Будь-яка допомога буде дуже вдячна.
Редагувати:
Дякую всім за відповіді! Ваші відповіді допомогли мені краще зрозуміти ці поняття. Я не думаю, що його ще повністю не натиснули, але я перегляну цю тему в майбутньому, дякую!
putStrLn не має побічного ефекту; він просто повертає IO-дію, та сама дія IO для аргументу "Hello World"незалежно від того, скільки разів ви викликаєте putStrLn.
helloworldце не була б дія, яка друкує Hello world; це було б значення, повернене putStrLn після його друку Hello World(а саме ()).
helloWorld = Console.WriteLine("Hello World");. Ви просто містити Console.WriteLine("Hello World");в HelloWorldфункцію , яка буде виконуватися кожен раз, коли HelloWorldвикликається. Тепер подумайте, що helloWorld = putStrLn "Hello World"робить helloWorld. Він присвоюється монаді IO, який містить (). Після того, як ви зв’яжете це, >>=він лише потім виконає свою діяльність (друкує щось) і надасть вам ()праворуч оператора прив'язки.
helloWorldпостійність, наприклад, поле чи змінну в C #. Немає жодного параметра, до якого застосовуєтьсяhelloWorld.