Недавно я начал изучать 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.