Нещодавно я почав вивчати 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
.