Недавно я начал изучать Haskell, потому что хотел расширить свои знания по функциональному программированию, и я должен сказать, что я действительно люблю это до сих пор. В настоящее время я использую ресурс «Основы Haskell, часть 1» по Pluralsight. К сожалению, мне сложно понять одну конкретную цитату лектора о следующем коде, и я надеялся, что вы, ребята, сможете пролить свет на эту тему.
Сопровождающий код
helloWorld :: IO ()
helloWorld = putStrLn "Hello World"
main :: IO ()
main = do
helloWorld
helloWorld
helloWorld
Цитата
Если в do-блоке выполняется одно и то же действие ввода-вывода несколько раз, оно будет выполняться несколько раз. Таким образом, эта программа печатает строку «Hello World» три раза. Этот пример помогает проиллюстрировать, что putStrLn
это не функция с побочными эффектами. Мы вызываем putStrLn
функцию один раз, чтобы определить helloWorld
переменную. Если putStrLn
бы был побочный эффект печати строки, он напечатал бы только один раз, и helloWorld
переменная, повторенная в основном блоке do, не имела бы никакого эффекта.
В большинстве других языков программирования такая программа выводит «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
не имеет побочных эффектов; он просто возвращает действие ввода-вывода, то же действие ввода-вывода для аргумента, "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
.