Как установить haskell на windows 10

Обновлено: 03.07.2024

Наконец-то я добрался до этой темы. А то слух, знаете ли, всё громче и громче, а что к чему - знают не все. В общем, решил я разобраться с новым Haskell-инструментом под названием stack .

О чём идёт речь

Утилита stack - это новый инструмент от команды FP Complete, предназначенный для работы с Haskell-проектами. Штуковина очень молодая (первая версия датируется июнем сего года), однако шуму наделать уже успела.

Постойте, скажете вы, у нас же есть старый добрый cabal ! Да, есть, но, как показала практика, не такой уж он и добрый. И вот теперь настал его смертный час, ибо к нам пришёл stack …

Замена Cabal?

Определимся с понятиями. Когда мы слышим слово “кабал” - речь может идти о:

  1. спецификации Cabal (“Common Architecture for Building Applications and Libraries”) и формате метаданных Haskell-проекта. Тот самый формат, который мы видим в файле с расширением .cabal ;
  2. реализации спецификации Cabal в виде библиотеки Cabal;
  3. утилите cabal-install , в виде знакомой нам команды cabal .

Так вот утилита stack - это замена утилите cabal-install . Больше не будет никаких cabal update и cabal sandbox init . Кстати, некоторые ошибочно полагали, что stack представляет собой надстройку над cabal-install и скрыто использует последнюю, однако это не так: stack использует Cabal-библиотеку (см. выше пункт 2), но никак не соприкасается с cabal-install . Иными словами, вы можете спокойно удалить cabal-install с вашего компьютера и забыть о ней навсегда.

Зачем это было нужно

По результатам большого опроса, проведённого среди множества коммерческих пользователей Haskell, главной болью при работе с Haskell-проектами была-таки cabal-install . Для этой боли даже название придумали: “cabal hell”. А всё дело было в сложных/перекрёстных зависимостях между (многочисленными) пакетами, задействованными в ваших проектах. Фундаментальная проблема cabal-install такова:

То, что работает сегодня, может перестать работать завтра.

Естественно, такое положение дел не устраивало сообщество, а в особенности тех, кто уже использовал Haskell в коммерческих проектах. Никому не хочется столкнуться с ситуацией, когда, после очередного cabal update , проект, прекрасно собирающийся вчера вечером, перестаёт собираться сегодня днём. Подобная непредсказуемость неизбежно разрушает доверие.

Были предприняты попытки решить указанную проблему. В cabal-1.18 были введены песочницы, а в cabal-1.20 - команда cabal freeze . Теперь проекты могли быть изолированными друг от друга, а пакетные зависимости можно было заморозить. И проблемы действительно уменьшились, но, к сожалению, не ушли. Поэтому команда FP Complete создаёт stack . Цель этого проекта - избавить мир от cabal hell , раз и навсегда. А заодно максимально упростить работу с проектами.

Поехали

Идём сюда и скачиваем stack для своей ОС. На момент написания данной статьи последней версией была 1.2.0 , датируемая 6 июля. После скачивания архива распаковываем его - и вот он наш файлик. Переименовываем его в stack , делаем исполняемым, копируем куда-нибудь в PATH (я положил в /usr/local/bin ) - и можно работать.

Начнём с пустышки

Команда new создаёт простейший проект-пустышку в текущем каталоге:

Перед нами - самый обыкновенный Haskell-проект. Кстати, он прямо сейчас, без каких-либо дополнительных манипуляций готов к сборке, в отличие от проекта, создаваемого с помощью cabal init .

Самая важная часть, которой не было раньше - файл stack.yaml . Заглянем в него:

Обратите внимание на последнюю строчку, ибо она очень, очень важна. lts-2.15 - это версия нашей Haskell-экосистемы. LTS - от “Long Term Support” - представляет собой фиксированный набор Haskell-пакетов. Но что значит “фиксированный набор”? Поясню.

Stackage

Как мы знаем, наш любимый Hackage содержит очень много пакетов: на данный момент их чуть более 8400 штук. Но будет честными - далеко не всё из этой кучи пригодно для реального применения. Многие из пакетов - сугубо экспериментальные (читай “игрушечные”), а есть и вообще заброшенные. Поэтому друзья из FP Complete придумали Stackage, от “Stable Hackage”.

Идея в следующем: отобрать часть конкретных пакетов - и закрепить их в своего рода снимке (snapshot), присвоив этому снимку версию. Например, снимок версии 2.15 включает в себя 1066 пакетов, причём версия каждого из них явно указана (взгляните на список).

Именно благодаря этому мы избавляемся от упомянутой выше непредсказуемости. Версия lts -снимка однозначно определяет версию каждого пакета, используемого в нашем проекте. Поэтому когда N программистов, работающих с неким проектом, используют одну и ту же версию lts -снимка - у них всё гарантированно работает (как сегодня, так и завтра).

Это особенно полезно при расширении разработки. Пришёл новый человек в команду - никаких проблем с вечно обновляющимися пакетами: он просто берёт ту же версию снимка, что и все остальные коллеги, собирает - и у него всё ок.

Собираем

Пора собрать наш проект:

В начале происходит загрузка “lts-2.15 build plan”, чтобы stack понял, с какими версиями пакетов следует работать в данном проекте. А теперь обратите внимание на последнюю строчку: stack сообщает нам о несоответствии версий GHC. На моей машине стоит 7.8.3, однако ожидается версия 7.8.4. Заглянем на lts-страницу - так и есть:

Данный снимок был проверен с использованием 7.8.4, а следовательно, эту версию и нужно использовать. Однако на моей машине, в рамках последней Haskell Platform, установлена версия 7.8.3. Что же делать? Следует установить версию 7.8.4 (спасибо, Кэп!).

Ставим нужный компилятор

К счастью, возможность установки нужного компилятора входит в обязанности stack ! Да-да, он и это умеет. Более того, он сам подсказал нам нужную команду. Вспомните ту самую последнюю строчку, в самом конце: “Try running stack setup”. Сделаем же это:

Немного терпения - и новый компилятор готов к использованию. Обратите внимание, что установлен он в скрытый каталог .stack , созданный в вашем домашнем каталоге. Следовательно, никаких конфликтов с уже имеющимся компилятором не будет:

Новая версия 7.8.4 будет использоваться исключительно в процессе сборки нашего проекта. А кстати, вдруг я вас обманываю? Как мы можем проверить версию реально используемого компилятора? Очень просто, ведь stack умеет запускать интерпретатор ghci :

Та-дам! Действительно 7.8.4.

Теперь уже точно собираем

Как видите, в корне проекта появился скрытый каталог .stack-work , в котором и осуществляется вся сборка. Взгляните, куда установилась наша программка:

Как видите, указана не только версия используемого компилятора, но и версия используемого lts -снимка.

Проверяем версии пакетов

Итак, собрали. А теперь убедимся в правоте наших ожиданий в отношении версий используемых пакетов.

Раньше версии пакетов (или диапазоны версий) указывались в .cabal -файле, в секции build-depends :

Теперь же, как мы помним, версии пакетов определяются используемым нами lts -снимком. Проверим это.

Я воспользуюсь одним из своих блогов, создаваемых, как многие знают, с помощью hakyll . Проект зависит от маленькой библиотеки split , помогающей разделывать строчки на кусочки. lts -снимок версии 2.15 содержит указание версии:

Итак, используется 0.2.2. А теперь я сделаю вид, что напутал с версиями и указал в .cabal -файле следующее:

На самом деле, версия 0.2.2 является последней, но суть не в этом. Суть в том, что проект не соберётся, потому что stack строг и аккуратен по отношению к версиям.

Первое, на что следует обратить внимание - новая команда. Мы используем stack init , потому что собираемся использовать stack для уже существующего Haskell-проекта. stack создаёт в его корне уже знакомый нам файл stack.yaml . И кстати, если в корне вашего проекта есть cabal -песочницы или файл cabal.config - смело удаляйте всё это.

Сразу после создания .yaml -файла stack проверяет готовность проекта быть собранным в соответствии с lts -снимком версии 2.15. И тут - неприятный, но вполне ожидаемый результат:

Версии пакета в .lts -снимке и в .cabal -файле различаются, поэтому сборка не пройдёт. Решение - убрать указание версий из .cabal -файла (ещё раз спасибо, Кэп!). Больше никакой путаницы - версии всех используемых пакетов явно указаны в lts -снимке, и нигде более.

Больше компиляторов, хороших и разных

Ну что ж, раз можно поставить дополнительный “локальный” компилятор, исходя из версии экосистемы конкретного проекта, значит, можно поставить и несколько компиляторов.

Допустим, я хочу поэкспериментировать с новым GHC 7.10.1 с существующим проектом. Перехожу в проект:

Теперь открываем stack.yaml и заменяем последнюю строчку на:

Оказывается, lts -снимок - не единственная возможность указания Haskell-экосистемы. LTS прекрасно подходит для серьёзных долгоживущих проектов, но для экспериментаторов, предпочитающих быть на гребне волны, подойдёт одна из ночных сборок. В данном случае - сборка от 12 июля сего года. Живёт она здесь. Откроем её:

Stackage Nightly 2015-07-12 - GHC 7.10.1

То, что нам нужно! Раз данная сборка проверена с помощью 7.10.1, то при выполнении команды stack setup произойдёт установка именно этой версии компилятора:

И теперь у нас есть два разных компилятора, не мешающих друг другу. Соответственно, все мои проекты, зависящие от 7.8.4, будут использовать только его, а проекты, зависящие от 7.10.1 - его. Никакой путаницы.

А куда он ставит пакеты?

До появляения cabal sandbox все пакеты ставились в глобальное пространство, и это было ужасно. Идея песочницы частично решила проблему: каждый проект теперь скрыто включал свою собственную песочницу, в которую устанавливалось всё, необходимое для данного проекта.

Вроде бы неплохое решение, но оно грубое в силу своей избыточности. Представьте себе, что у вас на машине есть три yesod -проекта. Соответственно, у вас появится три песочницы с тремя полными копиями всех пакетов, входящих в yesod -зависимости (кто работал с yesod , тот знает, что зависимостей этих, мягко выражаясь, много). Во-первых, попусту растрачивается дисковое пространство, а во-вторых, при появлении четвёртого yesod -проекта (ну вот любите вы yesod , почему бы и нет?) весь yesod будет заново установлен в чертвёртую песочницу. И особенно обидно будет при условии, если во всех четырёх проектах используется одна и та же версия yesod …

В stack всё умнее. Больше никаких избыточных копий пакетов внутри каждого из проектов. Теперь пакеты устанавливаются в единое глобальное место, а именно в упомянутый ранее скрытый каталог .stack в вашем домашнем каталоге. Но! Пакеты больше не валятся в одну кучу. Напротив, они устанавливаются иерархично, в соответствии с lts -снимками (ну и ночными сборками, если таковые используются).

Вот они, наши снимки. Глянем поглубже:

И вот они, все наши пакеты. Из пути сразу понятно, о каком снимке идёт речь и какая версия компилятора используется.

Таким образом, если упомянутые ранее три yesod -проекта используют одну и ту же версию lts -снимка - скажем, 2.15 - тогда использованы будут пакеты из каталога

/.stack/snapshots/x86_64-osx/lts-2.15/7.8.4/ . Если же четвёртый yesod -проект будет использовать, скажем, одну из ночных сборок совместно с GHC 7.10.1, то будут использованы пакеты из

/.stack/snapshots/x86_64-osx/nightly-2015-07-12/7.10.1/ . Никаких излишних копий, и при этом никаких конфликтов.

За пределами снимка

Как было сказано выше, lts -снимки (равно как и ночные сборки) содержат не всё то, что есть на просторах Hackage. Ну а вдруг мой проект использует некий пакет, которого нет в используемом мною снимке! Что делать?

Допустим, мне понадобился какой-нибудь string-qq . Если я просто укажу его в своём .cabal -файле, при попытке сборки stack выразит свой категорический протест:

Поэтому открываем stack.yaml , ищем строчку:

и заменяем её на:

Готово. Теперь при сборке stack увидит, что данный пакет нужно искать не в используемом снимке, а напрямую в Hackage. Соответственно, если мне вдруг понадобится более одного внешнего пакета, я просто дописываю их следом:

И всё заработает.

Установка в удобное место

Иногда после сборки проекта бывает удобно установить исполняемый файл приложения в какое-нибудь доступное место. Для этого служит команда install :

/.local/bin/ добавлен в PATH, то приложение будет немедленно доступно напрямую. Весьма удобно.

Вывод

Вывод только один - классную штуку сделали друзья из FP Complete. Лично я перевожу на stack все мои проекты. Прощай, cabal !

Кстати, если вы работаете на Linux - для вас хорошая новость: для Ubuntu, Debian, CentOS/Red Hat и Fedora уже готовы соответствующие пакеты. Ну а нам, маководам, осталось дождаться добавления stack в brew … ;-)

Как познать Haskell

Этот документ — рекомендованный путь к изучению языка Haskell, основанный на опыте помощи другим.

Это руководство доступно на других языках:

Не мучайтесь над одним топиком, который вы не можете понять сразу. Двигайтесь дальше!

Будьте дружелюбны и вежливы. Грубость и хамство испугает собеседника и оттолкнет от участия в общении.

Слабая, неконструктивная критика удовлетворяет лишь критикующего, но не помогает критикуемому.

Не описывайте вещи как «легкие» или «тривиальные». Вы заставляете людей чувствовать себя ужасно за то, что они усердно и много работают ради своего прогресса. Медленные в обучении люди зачастую самые дотошные, этому наоборот надо радоваться!

Не симулируйте удивление. Не изображайте удивление, когда кто-либо говорит, что он не знает что-то. Он будут чувствовать себя ужасно, а вы не получите ничего, кроме резкости.

«Ну, на самом деле». Когда кто-либо говорит что-то почти — но не совсем — верное, а вы говорите «ну, на самом деле. » и даете лишь мелкую правку. Это особенно раздражает, когда поправка не относится к основной теме разговора. Это не значит, что этот канал не про поиск правды или что нам все равно на точность. Просто почти все «ну, на самом деле» являются показухой, а не поиском правды.

Никаких -измов. Расизм, сексизм, гомофобия, трансофобия и другие виды фобий не приветствуются и не будут приняты терпимо.

Правила хорошего тона от Recurse Center. Спасибо за их публикацию Recurse Center.

Что такое Haskell, GHC и Cabal?

Haskell — это язык программирования, изложенный в спецификациях, последняя версия которых опубликована в 2010 году. Эта спецификация доступна как онлайн-документ.

GHC — это самый популярный способ работы с языком Haskell. Он включает в себя компилятор, REPL (интерпретатор), пакетный менеджер и другие полезные вещи.

Cabal позволяет управлять проектами и разрешает зависимости. При помощи него вы устанавливаете и создаете проекты, обычно в песочницу (изолированное окружение).

Cabal аналогичен Bundler в Ruby, pip в Python, NPM в Node и так далее. GHC управляет пакетами сам, Cabal решает какие версии устанавливать.

НЕ УСТАНАВЛИВАЙТЕ HASKELL PLATFORM

Установка GHC и Cabal

Этот PPA лучший, и именно его я использую на всех моих серверах и локальных машинах с Linux.

После этого, добавьте следующие пути к вашему $PATH (bash_profile, zshrc, bashrc, и т. п.):

Опционально: вы можете добавить также .cabal-sandbox/bin к вашему пути. Код, который вы разрабатываете, будет доступен вам из командной строки. Это работает только тогда, когда ваша текущая рабочая папка — песочница cabal.

Использование Ubuntu PPA

Если вы не используете стабильный дистрибутив, вы можете повторить все те же шаги, что и для Ubuntu, но вам надо будет выполнить дополнительную команду. Сразу после sudo add-apt-repository -y ppa:hvr/ghc выполните:

Для остальных версий Debian, просто замените все jessie именем вашей версии в команде выше.

Если по какой-то причине файл /etc/apt/sources.list.d/hvr-ghc-jessie.list не существует, то /etc/apt/sources.list должен содержать строку со ссылкой вроде этой:

Замените jessie на trusty в этой строке.

Сборка из исходников

Вы можете использовать это руководство, написанное для Mac OS X:

  • Выставьте ваш префикс соответственно, когда конфигурируете ghc.
  • Вместо того, чтобы забирать бинарник cabal-install , скачайте исходный код и запустите скрипт bootstrap.sh .

Чтобы установить Haskell 7.8.4 из неофициального репо (Fedora 22+ будут содержать его в официальном):

Как указано на странице petersen/ghc-7.8.4 этот ghc не может быть установлен вместе с Fedora/EPEL ghc.

Чтобы установить Haskell из официального репо на Arch Linux, выполните:

На Gentoo вы можете установить индивидуальные компоненты Haskell Platform через Portage. Если вы используете ACCEPT_KEYWORDS=arch (вместо ACCEPT_KEYWORDS=

arch ), Portage установит древние версии различных компонент Haskell. Помня это, если вы используете ACCEPT_KEYWORDS=arch , добавьте следующие строки в /etc/portage/package.keywords .

Как только это сделано,

Gentoo хранит «стабильную» (читай «старую») версию cabal-install в дереве Portage, так что, если вы хотите использовать более современную версию cabal-install , выполните (заметьте, что слеши здесь нужны)

Вы установили cabal глобально через Portage и локально в вашей домашней директории с cabal-install . Следующий шаг, это убедиться, что когда вы запускаете cabal в вашем терминале, ваша оболочка запускает последнюю версию в вашей домашней директории. Вам нужно добавить следующие строки к конфигурационному файлу вашей оболочки.

Если вы не знаете, какая оболочка у вас используется, то скорее всего это Bash. Если это Bash, то файл, в который вам надо добавлять эти строки —

/.bashrc . Если вы используете Z-shell, то это

/.zshrc . Вы можете понять, какая оболочка у вас используется, запустив:

Я использую zsh, так что вывод этой команды у меня выглядит как zsh .

После всего этого вы захотите установить дополнительные инструменты alex и happy .

Поздравляю! Теперь у вас рабочий Haskell!

Установите GHC для Mac OS X приложение, которое включает в себя GHC и Cabal. Оно предоставляет инструкции, как добавить GHC и Cabal в ваш путь, после того как вы скопируете приложение .app куда-либо.

Выполните установку бинарников, которая описана ниже, для этого архива.

    способен скомпилировать network и т. п. Технически, это бета версия, но должна работать для тех, кто читает это руководство.

Не забудьте запустить установщик как администратор, так как он захочет установить файлы в Program Files.

Пользователям других Linux дистрибутивов

Скачайте последние бинарники Cabal и GHC:

Пользователям других Unix-подобных систем

Скачайте GHC и Cabal из вашего пакетного менеджера, затем добавьте

/.cabal/bin в ваше $PATH . После этого обновите cabal и установите дополнительные инструменты alex и happy .

Как я должен изучать Haskell?

Основная рекомендация, это читать лекции и выполнять все упражнения/домашние задания для Spring 13 версии курса cis194. Затем то же для курса FP. На оба курса ссылки представлены ниже. Все остальное может быть рассмотрено как опциональное, и вы просто будете знать куда смотреть по определенной теме.

Курс Yorgey cis194

Выполните его в первую очередь, это лучший путь получить представление о Haskell

Курс от Brent Yorgey, это лучшее, что я пока нашел. Этот курс ценен тем, что он не только научит вас писать базовый код на Haskell, но и также поможет вам понять комбинаторы парсера.

Единственная причина, по которой вам не стоит начинать с курса cis194, это если вы не программист или вы неопытный программист. В этом случае, начинайте с книги от Thompson и после этого уже курс cis194.

Этот курс мы рекомендуем выполнять после курса Yorgey cis194.

Этот курс укрепит и добавит опыта реализации абстракций, представленных в курсе cis194. Эта практика критически важна для комфортного использования в дальнейшем таких абстракций как Functor/Applicative/Monad/и т. п. в Haskell. Выполнение cis194 и затем FP курсов представляет собой основную рекомендацию моего руководства и того, как научить любого языку Haskell.

Дополнительный курс после cis194 и FP

Предоставляет больше информации по продвинутым темам

Это онлайн курс от Bryan O’Sullivan, который он преподает в Стенфорде. Если вы не знаете кто он такой, взгляните на половину библиотек, от которых зависят все приложения на Haskell, и вы увидите его имя в их авторах. Если вы уже закончили курс Yorgey, особого внимания в этом курсе заслуживают разделы о фантомных типах, контроле потоков информации, расширениях языка, конкурентном выполнении, pipes и линзах.

Специфичные топики Haskell

Эти источники не были проверены на учащихся так, как cis194 и FP, но с их помощью вы поймете с чего начинать изучение определенной темы. Они включают продвинутые и сложные темы и топики посвященные инструментам и текстовым редакторам.

Что делает <- / do / синтаксический сахар включения списков?

Для понимания списков и свертки

Для изучения некоторых из стандартных классов типов

Полезно для понимания Functor , Applicative , Monad , Monoid и других классов типов в целом, а также немного специфичной для Haskell теории категорий:

Laziness, strictness, guarded recursion

Книга Marlow про параллелизм и конкаренси содержит одно из лучших представлений laziness и нормальных форм, которые я нашел. Используйте другие источники, если не поймете сразу из этого.

Haddocks for System.IO.Unsafe.unsafePerformIO При прочтении, обратите внимание на реализацию unsafeDupablePerformIO

Комментарий с обсуждения на Reddit от glaebhoerl

Интересное замечание: GHC должен скрывать отображение токена статуса абстрактного типа IO, потому что токен статуса должен все время быть использован линейно (не быть дуплицирован или сброшен), но система типов не может принудительно этого делать. Clean, другой ленивый подобный Haskell язык, имеет типы, гарантирующие уникальность (которые подобны линейным типам и возможно отличаются, но я не знаю как), и они разкрывают передачу в Мир напрямую и предоставляют (не абстрактную) IO монаду только для соблюдения соглашения.

Interesting side note: GHC needs to hide the state token representation behind an abstract IO type because the state token must always be used linearly (not duplicated or dropped), but the type system can’t enforce this. Clean, another lazy Haskell-like language, has uniqueness types (which are like linear types and possibly different in ways I’m not aware of), and they expose the World-passing directly and provide a (non-abstract) IO monad only for convenience.

Монады и трансформеры монад

Не делайте этого пока вы не поняли классы типов Monoid, Funcor и Applicative!

Реализуйте монады из стандартной библиотеки (List, Maybe, Cont, Error, Reader, Writer, State) для себя, чтобы понять их лучше. Затем, может быть, напишите монадный интерпретатор для маленького языка выражений используя документ Monad Transformers Step by Step (упомянут в «трансформеры монад» ниже).

Написание многих интерпретаторов просто изменяя монаду для изменения семантики может помочь лучше понять, что происходит.

Также, реализуйте Control.Monad . Функции типа mapM или sequence — хорошая возможность попрактиковаться в написании общего кода монад.

Курс FP может быть использован как руководство для этого, он также включает написание своего собственного Applicative.

Комментарии на Reddit от htmltyp и Crandom.

Комментарий на Reddit от jozefg.

Тестирование, тесты, спеки, generative/property тестирование

Это руководство от Kazu Yamamoto — просто фантастичecкое.

Simple-Conduit: Хорошая простая библиотека для изучения, как работает стриминг IO в целом, знания, применимые также к таким библиотекам как Pipes и Conduit.

Парсинг в Haskell

Руководство по Parser комбинаторy для Haskell с использованием Parsec

Парсинг и генерация JSON

Aeson — это стандартное решение для парсинга JSON в Haskell. Доступно из hackage и github.

Мы не можем начать изучение языка без испытательного полигона. Установим Haskell.

Сделать это можно несколькими способами, мы выберем самый удобный. Называется он The Haskell Tool Stack. Эта маленькая утилита — всё, что вам понадобится для работы с Haskell.

Haskell — кроссплатформенный язык, работающий и в Linux, и в macOS OS X, и даже в Windows. Однако в 2008 году я навсегда покинул мир Windows, поэтому все последующие примеры взаимодействия с командной строкой подразумевают Unix-way. Впрочем, если вы всё-таки используете Windows, будьте уверены — всё описанное ниже заработает и у вас.

Вся конфигурация и примеры кода опробованы мною на Ubuntu 16.04.1.

Устанавливаем

Идём сюда и забираем нужную нам версию. Общий Unix-вариант установки предельно прост:

Готово. После установки нам будет доступна команда stack , и она — наше всё.

На момент написания книги я использовал stack версии 1.4.0. Если у вас более старая версия — непременно обновитесь. Если же более новая — у вас что-нибудь может работать не совсем так, как описано ниже, поскольку stack всё ещё активно развивается.

Главное (но не единственное), что умеет делать stack , это:

  1. Разворачивать инфраструктуру.
  2. Собирать проекты.
  3. Устанавливать библиотеки.

Haskell-инфраструктура — экосистема, краеугольным камнем которой является ранее упомянутый компилятор GHC. Haskell является компилируемым языком: приложение представляет собой обыкновенный исполняемый (англ. executable) файл.

Haskell-проект — среда для создания приложений и библиотек.

Haskell-библиотеки — кем-то написанные решения, спасающие нас от изобретения велосипедов.

Разворачиваем инфраструктуру

В результате на ваш компьютер будет установлена инфраструктура последней стабильной версии. Жить всё это хозяйство будет в только что созданном каталоге

/.stack/ . Именно поэтому устанавливать инфраструктуру для последующих Haskell-проектов вам уже не придётся: единожды развернули, используем всегда. Пока вам не нужно знать об устройстве этой инфраструктуры, воспринимайте её как данность: теперь на вашем компьютере живёт Haskell.

Hi World

Создадим наш первый Haskell-проект:

Здесь real — название проекта. В результате будет создан каталог real , внутри которого мы увидим это:

Теперь переходим в каталог real и собираем проект командой:

Запомните эту команду, мы будем использовать её постоянно. В результате сборки появится файл real-exe . Располагается он внутри скрытого каталога .stack-work в корне проекта. Чтобы сразу его запустить, не копаясь во внутренностях этого скрытого каталога, используем команду:

Команда stack exec запускает программу (в данном случае real-exe ) внутри stack -окружения. В одной из последующих глав я подробнее расскажу об этом окружении. Впрочем, мы можем запустить нашу программу и напрямую, без stack . Исполняемый файл real-exe находится внутри скрытого каталога .stack-work в корне проекта. Например, на моём компьютере путь к исполняемому файлу такой:

Но можно и упростить себе жизнь, выполнив команду:

В результате исполняемый файл будет скопирован в каталог

/.local/bin (подразумевается, что такой каталог у вас уже имеется). Кстати, полезно добавить

/.local/bin в PATH , что позволит вам тут же запускать программу:

Вот мы и создали Haskell-проект и запустили нашу первую программу, выведшую строку someFunc . Но как же это работает? Пришла пора познакомиться с фундаментальной единицей проекта — модулем.

Модули: знакомство

Haskell-проект состоит из модулей. Модулем называется файл, содержащий исходный Haskell-код. Один файл — один модуль. Расширение .hs — стандартное расширения для модулей. В Haskell нет понятия «заголовочный файл»: каждый из модулей рассматривается как самостоятельная единица проекта, содержащая в себе разные полезные вещи. А чтобы воспользоваться этими вещами, необходимо один модуль импортировать в другой.

Откроем модуль src/Lib.hs :

В первой строке объявлено, что имя этого модуля — Lib . Далее в круглых скобках указан интерфейс данного модуля, то есть та его часть, которая видна всему миру. В данном случае это единственная функция someFunc , объявление и определение которой идёт далее, вслед за ключевым словом where . Пока вам не нужно знать о синтаксисе объявления и определений функции, в следующих главах мы разберём его тщательнейшим образом.

Теперь откроем модуль app/Main.hs :

Это модуль Main , главный модуль нашего приложения, ведь именно здесь определена функция main . С помощью директивы import мы включаем сюда модуль Lib и можем работать с содержимым этого модуля.

Запомните модуль Main , с ним мы будем работать чаще всего. Все примеры исходного кода, которые вы увидите на страницах этой книги, живут именно в модуле Main , если не оговорено иное.

Все модули в наших проектах можно разделить на две части: те, которые мы берём из библиотек и те, которые мы создали сами. Библиотеки — это уже кем-то написанные решения, в последующих главах мы познакомимся со многими из них. Среди библиотек следует выделить одну, так называемую стандартную библиотеку. Модули из стандартной библиотеки мы начнём использовать уже в ближайших главах. А одна из глав будет полностью посвящена рассказу о библиотеках: из неё мы подробно узнаем, откуда берутся библиотеки и как их можно использовать.

Для любопытных

До появления stack основным способом установки Haskell была так называемая Haskell Platform. Однако именно stack , несмотря на свою молодость (вышел в свет летом 2015 года), является предпочтительным путём в мир Haskell, особенно для новичков. Его настолько полюбили, что последние версии Haskell Platform включают в себя stack по умолчанию!

Как вы заметили, имена файлов с исходным кодом начинаются с большой буквы: app/Main.hs и src/Lib.hs . Строго говоря, это необязательно, можно и с маленькой буквы, однако для гармонии с именем модуля лучше придерживаться общепринятой практики и называть файл модуля по имени самого модуля:

И ещё. При создании проекта мы могли бы использовать схему simple вместо предлагаемой по умолчанию. Для этого проект нужно было создать командой:

где simple — имя схемы проекта. Дело в том, что команда stack new может создавать заготовки проектов для разных нужд. Простейшая из заготовок называется simple . В этом случае в проекте отсутствует модуль src/Lib.hs , а есть лишь src/Main.hs :

Да, мы могли бы воспользоваться данной схемой, однако в этом случае мы не увидели бы механизма импорта одного модуля в другой. Я рад, что вы познакомились с импортом уже сейчас, ведь в последующих главах мы будем постоянно использовать различные модули из многих библиотек.


Я замечательно провел время изучая Haskell в последние месяцы, и мне кажется, что сделать первые шаги в этом занятии сложнее, чем это могло бы быть на самом деле. Мне повезло работать в нужное время и в нужном месте, и в Facebook я прошел курс по Haskell от Bryan O'Sullivan, но Вы определенно сможете влиться в тему и без чужой помощи. Для этого можно поиграть в Haskell на сайте Try Haskell, а в конечном счете установить себе GHC.

Устанавливаем Haskell Platform (GHC)

The Haskell Platform — это Glasgow Haskell Compiler (GHC) и стандартная библиотека «в полной комплектации». GHC не единственный компилятор Хаскеля, но Вам нужен именно он. Другая реализация, достойная внимания, Hugs, подходит больше в академических целях, чем в практических.

Инструкция написана для пользователей Mac OS X 10.8 с установленным Homebrew (и свежей версией Xcode), но разобраться с тем, как сделать то же самое на других платформах с помощью Haskell Platform должно быть просто. Текущая версия Haskell Platform на данный момент 2012.4.0.0.

Устанавливаем Cabal

Cabal — это Общая Архитектура Сборки Приложений и Библиотек (Common Architecture for Building Applications and Libraries) для Хаскеля. В паре с Hackage, Cabal похож по смыслу на такие инструменты, как CPAN для Perl, pip для Python или же gem для Ruby. Вероятно, Вы будете разочарованы, но всё же он не так уж и плох.

Cabal устанавливает свои пакеты в

/.cabal/ , а скрипты уходят в

/.cabal/bin/ . Вам нужно добавить эти пути в переменную окружения PATH. Достаточно чего-то подобного, но все зависит от Ваших предпочтений (лично я для этих целей пользую

/.profile — прим. переводчика):


Прежде чем начать пользоваться cabal, нужно развернуть список доступных пакетов. Иногда Вам придется запускать эту команду, в частности перед установкой или обновлением пакетов.


На данный момент мы имеем

/.cabal/config без включенного профилирования библиотек. Вы наверняка позже захотите им воспользоваться, и если не включить его сейчас, то в будущем придется все пересобирать заново. Чтобы включить его, измените строчку -- library-profiling: False на library-profiling: True в файле


Самым первым Вашим пакетом должен стать инсталлятор Cabal:

Устанавливаем ghc-mod (улучшенная поддержка Emacs/Vim)

ghc-mod пригодится Вам для интеграции GHC с Emacs или Vim. Того же самого эффекта можно достичь в Sublime Text 2 и ghc-mod с помощью SublimeHaskell. Я пока что пользовался только интеграцией с Emacs. Пользователи Vim могут воспользоваться hdevtools, т.к. он гораздо быстрее, и настолько же точен (см. комментарий kamatsu)


Настройку Вашего собственного Emacs я освещать не стану (но можете воспользоваться моим текущим

Устанавливаем Cabal-dev (песочница для сборки)

Cabal-dev — это инструмент, который упростит Вам установку приложений на Хаскеле. Он похож на virtualenv для Python и rvm для Ruby, но подход к использованию различается. Он спасет Вас от «кабальского ада», в котором ни у кого не получается устанавливать одни пакеты из-за конфликтов с зависимостями других.

Используйте cabal-dev вместо простого cabal для сборки везде, где это возможно. Главный компромисс состоит в том, что Вам придется тратить (гораздо) больше времени на компиляцию пакетов, которые уже и так были установлены где-то в другом месте (и забивать дисковое пространство), но это безусловно справедливая плата.


В данный момент ведутся некоторые работы над влючением поддержки Сборок в Песочнице и Изолированных Окружений в cabal-install, так что информация о cabal-dev, которая есть в этом посте, потеряет актуальность через несколько месяцев (лет?).

Установка инструментов при помощи cabal-dev

Если Вам хочется попробовать какой-нибудь инструмент, но желание загрязнять свою инсталляцию Хаскеля отсутствует, в таком случае нужно просто использовать cabal-dev. По умолчанию, песочница cabal-dev находится в ./cabal-dev , но Вы можете держать ее где угодно. В этом примере я установлю darcs 2.8.2 (распределенная система контроля версий, написанная на Хаскеле) в папку /usr/local/Cellar/darcs/2.8.2 , и попрошу Homebrew сделать для меня симлинки. На других платформах Вам скорее всего придется использовать собственную структуру директорий, а также вручную редактировать PATH.


Тыдыж! Теперь darcs лежит в Вашем PATH, и больше не придется беспокоиться о конфликтующих версиях. Ну, к сожалению, конфликты все еще будут происходить, но теперь не так часто. В частности, cabal-dev устанавливает пакеты таким образом, что они выходят на самую верхушку выбранной песочницы. Это значит, что если два пакета обладают общими зависимостями (ОЧЕНЬ общими), то они спляшут джигу на симлинках друг друга, вплоть до таких вещей как файлы лицензионных соглашений и документации зависимостей. В таком случае использовать --overwrite можно почти безболезненно, но я рекомендую сначала прогонять с ключом --overwrite --dry-run . Это надоедает, но наверняка не испортит Вам целый день.

Если хочется увидеть доступные версии darcs, используйте use cabal info darcs и найдите секцию Versions available: .

Настройка GHCi

ghci — это интерактивный интерпретатор GHC (REPL, схожий с python или irb в терминале). За подробной документацией рекомендую обратиться к GHC Users Guide (Chapter 2. Using GHCi). Вы будете проводить там много времени, играя с кодом, так что предлагаю для начала укоротить приветствие. Оно выглядит так:


Когда Вы начнете импортировать модули, приветствие разрастется, и на самом деле это никому не нужно.


Можно также использовать команду :set prompt "h> " при каждом запуске GHCi, но это тоже лишнее.

Hackage хрупкий, но существуют (неофициальные) зеркала

Для этого нужно поменять строчку в


После изменений, нужно обновить список пакетов


И не забудьте вернуть все обратно спустя некоторое время!

Создаем проект (с помощью cabal-dev)

В конечном счете Вы бы и сами это осознали, но самый быстрый способ начать проект — начать его с cabal-dev. Вот что нужно сделать для простенькой программы.

Для собственных проектов, нужно убрать опцию -n , чтобы задать список необходимых опций вручную. Опция -n использует все настройки по умолчанию и ни о чем Вас не спрашивает.

Это сгенерирует файлы Setup.hs и hs-hello-world.cabal . Следующим шагом нужно изменить строчку main-is: , чтобы кабал знал, из какого исходника собирать исполняемый файл. Конечный результат должен получиться таким:

hs-hello-world.cabal

Затем создайте HelloWorld.hs , с таким содержимым:

HelloWorld.hs

Вот что нужно, чтобы собрать и «установить» программу в текущей песочнице:

Исполняемый файл получается великоват, но также он статически линкован. Можно скопировать его на любую машину с такой же операционной системой и архитектурой, и он просто будет работать.

Можно сэкономить немного времени, пропустив шаг установки:


Так как у проекта нет зависимостей, которые нужно устанавливать, можно немного срезать углы.

Например, запустить с помощью интерпретатора, без компиляции:

Да и вовсе можно собрать его без cabal-dev (или cabal ):


Но для более сложного проекта, можно использовать cabal-dev ghci (после cabal-dev configure && cabal-dev build ). Прошу заметить, что в этом случае код будет загружен в интерпретатор автоматически:

Основы GHCi

Некоторые базовые трюки GHC которые хорошо бы знать. Помимо тех, которые я указал здесь, советую изучить Chapter 2. Using GHCi.

:t показывает тип выражения
:i показывает информацию о названии (function, typeclass, type, . )
:m добавляет модуль в текущую область видимости
:l подгружает модуль, :r перезагружает

Рекомендованное чтение

Я отметил для себя следующие книги и сайты полезными, пока учил Хаскель самостоятельно.

Книги

    Эта книга оказалась для меня великолепной стартовой точкой, я рекомендую ее первой к прочтению. Она не заходит слишком глубоко, чтобы дать Вам ощущение ДЕЙСТВИТЕЛЬНО полного понимания GHC, но после ее прочтения я стал чувствовать себя комфорно в написании и понимании кода на Хаскеле.
    Это увесистая книга и по размерам, и по глубине, но это не мешает ей быть доступной даже новичку. Она охватывает множество вещей из Реального Мира: написание теста, профилирование, IO, параллелизм и т.д. Я до сих пор ее изучаю, но эта книга обязательна к прочтению.
Сайты
    — был такой курс по Haskell в Стенфорде, который преподавали David Mazières и Bryan O'Sullivan. Он похож (но его охват шире) на тот курс, который я прошел в Facebook. Конспекты лекций и программа — просто фантастические, читайте их все! отличная вещь для погружения, там Вы найдете все эти ссылки + ГОРАЗДО больше. Рассчитывайте потратить там много времени! содержит некоторые маленькие задачки, над которыми можно поработать. Он во многом похож на Euler project. Их довольно просто решить после прочтения LYAH. отличный ресурс для изучения множества тайпклассов Haskell Platform — это поисковик по Haskell API, поддерживающий поиск по сигнатурам типов! Я провел за ним очень много времени. еще один поисковик, подходит для случаев, когда невозможно найти необходимую информацию с помощью Hoogle — еженедельная рассылка Хаскеля, которая собирает в себе ключевые моменты из мэйл листов, вопросы со stackoverflow, реддит и т.п.. — сабреддит по Haskell — вопросы по Haskell на stackoverflow, частенько достойны прочтения (если честно, очень часто там засиживаюсь после HWN) 13 лекций по Основам Функционального Программирования (на Хаскеле), рассказанные Dr. Erik Meijer (я еще их не посмотрел, но их советовал Adam Breen).

Читайте также: