Но не надо отчаиваться, не всё ещё потеряно. Оказывается, в языке Haskell есть весьма умная система для работы с функциями с побочными эффектами, которая чётко разделяет чисто функциональную и «грязную» части нашей программы. «Грязная» часть выполняет всю грязную работу, например отвечает за взаимодействие с клавиатурой и экраном. Разделив «чистую» и «грязную»части, мы можем так же свободно рассуждать о чисто функциональной части нашей программы, получать все преимущества функциональной чистоты, а именно – ленивость, гибкость, модульность, и при этом эффективно взаимодействовать с внешним миром.
До сих пор для того, чтобы протестировать наши функции, мы загружали их в интерпретатор GHCi. Там же мы изучали функции из стандартной библиотеки. Но теперь, спустя семь глав, мы наконец-то собираемся написать первую программу на языке Haskell! Ура! И, конечно же, это будет старый добрый шедевр «Привет, мир».
Итак, для начинающих: наберите в вашем любимом текстовом редакторе строку
>main = putStrLn "Привет, мир"
Мы только что определили имя >main
; в нём мы вызываем функцию >putStrLn
с параметром >"Привет, мир"
. На первый взгляд, ничего необычного, но это не так: мы убедимся в этом через несколько минут. Сохраните файл как helloworld.hs.
Сейчас мы собираемся сделать то, чего ещё не пробовали делать. Мы собираемся скомпилировать нашу программу! Я даже разволновался!.. Откройте ваш терминал, перейдите в папку с сохранённым файлом helloworld.hs и выполните следующую команду:
>$ ghc helloworld
>[1 of 1] Compiling Main ( helloworld.hs, helloworld.o )
>Linking helloworld …
О’кей! При некотором везении вы получите нечто похожее и теперь можете запустить свою программу, вызвав >./helloworld
.
>$ ./helloworld
>Привет, мир
ПРИМЕЧАНИЕ. Если вы используете Windows, то вместо выполнения команды >./helloworld
просто запустите файл helloworld.exe.
Ну вот и наша первая программа, которая печатает что-то на терминале! Банально до невероятности!
Давайте изучим более подробно, что же мы написали. Сначала посмотрим на тип функции >putStrLn
:
>ghci> :t putStrLn
>putStrLn :: String -> IO ()
>ghci> :t putStrLn "Привет, мир"
>putStrLn "Привет, мир" :: IO ()
Тип >putStrLn
можно прочесть таким образом: >putStrLn
принимает строку и возвращает действие ввода-вывода (I/O action) с результирующим типом >()
(это пустой кортеж). Действие ввода-вывода – это нечто вызывающее побочные эффекты при выполнении (обычно чтение входных данных или печать на экране); также действие может возвращать некоторые значения. Печать строки на экране не имеет какого-либо значимого результата, поэтому возвращается значение