Haskell

индекс
123,13

Изучай Haskell ради Добра! Введение

Добрый день. Думаю, вы встречались со ссылками на чудесную онлайн-книгу, «Learn Haskell for Good». Под катом можно ознакомиться с переводом раздела «Введение» из этого туториала.

Об учебнике

Добро пожаловать в «Learn You a Haskell for Great Good»! Если вы читаете эту статью, есть шанс, что вы хотите изучить язык Haskell. Что ж, вы пришли по адресу, но для начала давайте поговорим о самом учебнике.

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

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

Данное руководство нацелено на людей, которые уже имеют опыт в императивных языках программирования (C, C++, Java, Python...), но ранее не программировавших на функциональных языках (Haskell, ML, OCaml...). Хотя, бьюсь об заклад, что даже если вы не обладаете значимым опытом программирования, то такие умные малые, как вы, будут в состоянии следовать руководству и смогут изучить Haskell.

Канал #haskell на Freenode Network — это прекрасное место для вопросов, если вы почувствуете, что «застряли». Люди там чрезвычайно приятные, вежливые и сочувствуют новичкам.

Мои попытки изучать Haskell были неудачны, примерно пару раз, прежде чем я наконец-то ухватил суть, потому что все выглядело странно и я просто ничего не понял. И когда все прояснилось, после сложностей вначале, все пошло как по маслу. Думаю, я хочу сказать: Haskell — великий язык, и если вас интересует программирование, то вы действительно должны изучить его, и даже если в начале все выглядит запутанно. Изучение Haskell более похоже на первое изучение программирования — это очень занимательно! Оно заставляет мыслить иначе, что подводит нас к следующему разделу…

Так что же такое Haskell?

Haskell — это чистый функциональный язык программирования. В императивных языках результат получается от передачи компьютеру последовательности команд, который он затем выполняет. Выполняя ваши команды, компьютер может изменять свое состояние. Например, мы устанавливаем переменную A равной 5 и что-нибудь делаем, и затем устанавливаем ее равной чему-нибудь еще. Еще у вас есть операторы управления выполнением, чтобы повторять какие-то действия несколько раз. В чисто функциональных языках вы не говорите компьтеру как именно делать, скорее вы говорите, что представляет собой ваша проблема.

Факториал числа — это произведение целых чисел от 1 до этого числа, сумма списка чисел — это первое число плюс сумма всех остальных чисел, и так далее. Вы выражаете это в виде функций и не можете присвоить переменной A значение, а затем присвоить что-нибудь еще. Если вы сказали, что A равна 5, то нельзя позднее нельзя сказать, что она равна другому значению, потому что вы уже сказали, что она равна 5. В конце концов вы что, врун какой-нибудь?

В итоге, в чистых функциональных языках у функций отсутствуют побочные эффекты. Только одну вещь может cделать функция — это рассчитать что-нибудь и возвратить это как результат. Поначалу это выглядит как ограничение, но в действительности имеет положительные последствия: если функция вызывается дважды с одними и теми же параметрами — это гарантирует, что вернется одинаковый результат. Такие функции называются «чистыми» и не только позволяют компилятору получить информацию о поведении программы, но и дают возможность вам легко вывести (и даже доказать), что функция корректна, а также строить более сложные функции, объединяя их вместе с простыми.

Haskell — ленивый язык. Это означает, что язык не будет выполнять функции и проводить вычисления пока это действительно вам не потребовалось для вывода результата, если иное поведение не указано явно. Это хорошо согласуется с чистыми функциями и позволяет вам думать о программе как о наборе преобразований данных. Что, например, допускает такие отличные вещи, как бесконечные структуры данных.

Допустим, у вас есть неизменяемый список чисел xs = [1,2,3,4,5,6,7] и функция DoubleMe («УдвойМеня»), которая умножает каждый элемент на 2 и затем возвращает новый список. Если мы захотим умножить наш список на 8 в императивных языках, то сделаем так: DoubleMe(DoubleMe(DoubleMe(xs))), что при вызове, вероятно, получит список, создаст копию и вернет ее.

Затем получит список еще два раза и вернет результат. В ленивых языках программирования, вызов DoubleMe со списком, без форсирования получения результата, в программе скажет вам что-то типа: «Да-да, я сделаю это позже!». Но когда вы захотите увидеть результат, то первая функция DoubleMe скажет второй, что ей требуется результат, и немедленно! Вторая функция скажет третьей, и та неохотно вернет удвоенную 1, т.е. 2.

Вторая получит и вернет первой функции результат — 4. Первая увидит результат и выдаст вам 8. Так что потребуется только один проход по списку, и он будет выполнен только тогда, когда действительно необходим. Таким образом, когда ты хочешь что-то от ленивого языка, ты можешь просто взять входные данные и эффективно преобразовать и «подшить» их так, чтобы в конце они были похожи на то, что тебе надо.

Haskell — статически типизированный язык. Когда вы компилируете вашу программу, то компилятор знает, какой кусок кода — число, какой — строка и т.д. Это означает, что множество возможных ошибок будут обнаружены во время компиляции. Если вы захотите сложить вместе число и строку, то компилятор вам пожалуется. Haskell имеет очень хорошую систему типов, которая умеет делать вывод типов.

На практике это означает, что вам не нужно описывать типом в каждом куске кода, потому что система типов может вычислить это сама. Если, скажем, A = 5 + 4, то вы не говорите, что A — число, так как это может быть выведено автоматически. Вывод типов делает ваш код более универсальным. Если функция принимает два параметра и складывает их вместе, и при этом тип параметров явно не задан, то функция будет работать с любыми двумя параметрами, которые ведут себя как числа.

Haskell — ясный и выразительный язык, потому что он использует множество высокоуровневых идей; программы обычно короче, чем их императивные эквиваленты, их легче сопровождать, в них меньше ошибок.

Haskell был придуман несколькими действительно умными ребятами (кандидатами наук с PhD). Работа над языком Haskell началась в 1987 году, когда комитет исследователей собрался для разработки нового языка, который всех порвет. В 2003 году был впервые опубликован Haskell Report, что ознаменовало возникновение стабильной версии языка.

Что нужно для «погружения».

Текстовый редактор и компилятор языка Haskell. Вероятно, у вас уже установлен любымый редактор, так что не будем тратить на него время. На сегодня существуют два основных компилятора языка Haskell — это GHC (Glasgow Haskell Compiler) и Hugs. Я не буду заостряться на деталях их установки.

Для установки под Windows достаточно скачать инсталлятор, нажать несколько раз «Далее» и перезагрузить компьютер. В дистрибутиве Debian Linux всего-то надо: apt-get install ghc6 libghc6-mtl-dev и вы будете довольны. Mac у меня нет, но я слышал, что если у вас есть MacPort, то можно получить GHC выполнив sudo port install ghc. Кроме того, думаю, вы сможете попрограммировать на Haskell с этой идиотской однокнопочной мышью, хотя в этом я и не уверен.

GHC может принимать и компилировать файлы скриптов на языке Haskell (обычно у них расширение .hs), а так же имеет интерактивную среду, которая позволяет интерактивно взаимодействовать со скриптами. Все это интерактивно! Вы сможете вызывать функции из загруженных файлов и тут же получить результат. Во время обучения языку — этот подход намного проще и быстрее, чем компилировать и запускать раз за разом, когда меняется скрипт.

Интерактивная среда вызывается запуском ghci. Если, скажем, у вас в файле myfunctions.hs определены функции, то для их загрузки достаточно набрать l: myfunctions и легко с ними «поиграть», только если файл myfunctions.hs находится в том же каталоге, откуда был вызван ghci. При внесении изменений в скрипт достаточно снова выполнить :l myfunctions или просто :r, что то же самое, так как заново загружает текущий файл. Обычно, я делаю следующим образом, когда решаю потренироваться — объявляю функции в .hs файле, загружаю его, поиграюсь с функциями и вношу изменения в .hs файл, снова загружаю и так далее. Это именно то, чем мы тут и займемся.

Переведено толпой.
Оригинал (английский): Learn you a Haskell for Great Good: chapter — Introduction
Перевод: © plague, etranger, ventalf.
Перевод опубликован в комьюнити defun.ru.
+37
7 октября 2009, 14:44
50

комментарии (70)

+4
Setti #
ну хотябы мааааленький кусочек кода бы сюда :(
0
folone #
Так там же куча таких маленьких кусочков вроде…
0
Setti #
а для перевода не считается?
+3
warmaxx #
Мы его в универе изучаем, препод рассказывает что нам можно много чего написать, главное нужную библиотеку подключить и прочее.

Вот пример рекурсии (факториал):
f[] = [] // функция от пустого множества даст пустое монжество
f(0) = 0 // функция от 0 дает 0, мы как бы задаем константу.
f(1) = 1
f(n) = f(n-1)*n // рекурсивный вызов функции

вызов выглядит так:
f(4)
24
+2
Nc_Soft #
0! = 1, у вас это выдается?
+2
lam0x86 #
а что будет, если написать f(-1)? Как в хаскеле обстоят дела с обработкой ошибок?
+1
VoidEx #
Функции в Хаскеле нетотальны, так что можно определить частичную функцию. Будет выброшено исключение, которое может быть поймано в монаде IO (понятно, ведь реальное вычисление будет происходить именно там). Хорошим тоном будет написать
f _ = error "...".
0
VoidEx #
Как написали ниже, в данном конкретном случае будет исключение Stack overflow, я немного про другое ответил.
0
lam0x86 #
то есть для того, чтобы функция не работала для отрицательных чисел нужно написать что-то вроде этого
f(x) | x<0 = error "..."
?
+2
azm #
| x < 0 — это охранное выражение, в данном случае проще использовать аргумент _ (знак подчёркивания), как в комментарии выше, означающее любое совпадение.
0
azm #
В приведённом выше коде будет переполнение стека, так как рекурсия будет бесконечной:

    ERROR - C stack overflow
0
azm #
В коде выше ошибка — несоответствие типов: списочного и численного. Он вообще не заработает. А вот если написать так:
    f 0 = 0
    f 1 = 1
    f x | x > 1 = x * f (x - 1)
то при вызове:
    f (-1)
не произойдет удачного сопоставления с образцом x > 1, и соответственно это будет ошибкой.
0
lam0x86 #
Ошибка при компиляции? Если да, то что будет если подсунуть вместо -1 сложное выражение, значение которого невозможно определить при компиляции?
0
azm #
Сила Haskell в том, что он работает с неизменяемыми значениями. Однако существуют средства для работы с вводом выводом. Необходимо предусматривать все возможные случаи, тем более, что удобные средства для этого существуют. Такие как в комментариях выше.
0
VoidEx #
Позвольте поинтересоваться, в каком университете изучают Хаскель? Я вам завидую :)
0
folone #
Мм. Нас лиспу учили, например. В любом техническом языке обычно преподают какой-нибудь ФЯП.
0
folone #
техническом ВУЗе, простите.
0
Ferroman #
Не в любом.
0
folone #
Ок, поправлюсь, в любом, мне известном :)
0
Ferroman #
Завидую.
+1
msd #
С этого года на 1-м курсе в УрГУ, например.
0
orybak #
В ИТМО тоже. На 5м курсе, как мне помнится, был курс ФЯП. Немного рассказали про лисп. Более подробно читали хаскель. Было 5 дз
0
steck #
Вот сейчас СПБГУ МатМех, пятый курс. Правда дают его настолько отвратительно, что если бы я не изучал его раньше, то стал бы только плеваться. Но в целом синтаксис объясняют, задачки дают.
В общем перспективы есть.
0
warmaxx #
МГППУ
0
stas_agarkov #
В Белгородском государственном технологическом университете им. В. Г. Шухова на кафедре ПОВТиАС!
0
GooRoo #
ХНУРЭ — Харьковский национальный университет радиоэлектроники ;)

К сожалению, всего лишь 1 семестр.
+3
mylh #
Вот, рекомендую — Эволюция хаскель программиста: www.willamette.edu/~fruehr/haskell/evolution.html Множество кусков кода и все реализуют простую функцию n!
0
folone #
Очень классно, спасибо.
+2
sp1ne #
Мышь не идиотская!!! :'(

Хотя лан… — идиотская :)
+1
folone #
Тссс! Вдруг мако… воды заметят.
+1
akosarev #
интересно, а они еще продаются? :) Хочу себе однокнопочную мышку к маку…
0
dja #
Могу продать :) уж больно она мне не мила.
А вообще они до сих пор с каждым маком идут, но теперь они только выглядят как однокнопочные, а реально там две кнопки (зависит от того на какую сторону «одной кнопки» нажмешь).
+1
Evgeny_Shiryaev #
Для установки под Windows достаточно скачать инсталлятор, нажать несколько раз «Далее» и перезагрузить компьютер.


Ну вот зачем может понадобиться перезагрузка компьютера в этом случае? %)
0
lam0x86 #
Для надёжности =)
+9
shai_xylyd #
Это windows, здесь так принято :)
0
Setti #
Может быть Haskell ядро винды пересобирает под функциональную парадигму? o_O
+2
VoidEx #
Странно. Ни GHC, ни Haskell Platform (GHC + утилиты и набор библиотек) перезагрузки не требуют. Может быть, старые требовали?
0
warmaxx #
мы юзаем winhugs, запускается без инсталятора
0
hoodoy #
Возможно, для того чтобы заработали изменения внесенные в переменную окружения PATH, или как ее там… =)
0
folone #
Насколько мне известно, для этого достаточно перезапустить консоль.
0
IeN #
Мне вот интересно… а на хаскеле сложно сделать
большой реальный проект?
А то как язык он конечно хороший,
с хорошей теорией,
а вот практика не ясна
+2
VoidEx #
Ну сам GHC на Хаскеле написан. FFI удобный, язык мощный, на Hackage есть много всего, остальное можно достать через Си, вот только программистов на нём поискать надо.
0
GooRoo #
Прошу прощения, я непросвещенный студент… Что такое FFI? А то Википедия выдаёт страшные вещи =)
0
GooRoo #
Всё, кажется я понял из комментов ниже. Спасибо.
+3
siasia #
Просмотрев упомянутую в статье книгу я тоже считаю, что прочитав только её и усвоив основы функционального программирования, действительно практически невозможно реализовать какую-либо сложную систему. Но дело в том, что вышеупомянутая книга является только введением в Haskell(фактически она для тех, кто интересуются функциональным программированием, но вряд ли собирается отказываться от имперетивных языков в сложных системах).

Сам я изучал Haskell по Real World Haskell и могу сказать, что в этой книге упоминается множество аспектов Haskell, упущенных в Learn Haskell for Good(как раз и используемых в большинстве «Real World» приложений) таких как:

  1. 1. Регулярные выражения
  2. 2. Использование функторов для реализации ограниченного функционала монад — в частности используется для чисто функциональных парсеров
  3. 3. Юнит тестирование
  4. 4. Дополнительные библиотеки GHC для работы со словарями и массивами
  5. 5. Использование существующих монад и написание собственных — также даёт понимание как монадический код в do блоках укладывается в чистую функциональность Haskell.
    1. Reader Monad — используется для чтения конфигов
    2. State Monad — используется для хранения состояния(при этом не передавая его как аргумент монадической функции)
    3. Error Monad — бросаем ошибки внутри этой монады
    4. Writer Monad — логируем различные аспекты приложения
      --

  6. 6. Parsec — фрэймворк для парсинга(в том числе и синтаксического)
  7. 7. Собственно FFI
  8. 8. Трансформеры монад для оборачивание IO монады в State, Reader(что также очень нужно в реальной жизни)
  9. 9. Использование БД
  10. 10. Написание программ взоимодествующих с вебом
  11. 11. GUI программирование
  12. 12. Конкурентное программирование и программирование для многоядерных процессоров — рассматривается даже чисто функциональный параллелизм
  13. 13. Конкурентное программирование и программирование для многоядерных процессоров — рассматривается даже чисто функциональный параллелизм
  14. 14. STM(Software Transactional Memory) — библиотека, прозрачно решающая основные проблемы парралелизма внедряя транзакционность и поддержку инвариантов внутрь Haskell


Как видите список достаточно широк и охватывает почти все практики, используемые при реализации enterprise-систем.
0
GooRoo #
Параллелизм рассматривают дважды, если с первого раза не дошло?

P.S. Шутка (:
0
steck #
Хочу довавить, что для виндового пользователя скорее всего будет лучше устанавливать не просто GHC а уже Haskell Platform, которую будет весьма просто скачать и установить. Кроме того установится такая вещь как cabal и дальше устанавливать, например, eclupseFP будет совсем просто.
0
GooRoo #
Раз такое дело, осмелюсь пооффтопить:

Я пытался установить какую-то библиотеку с помощью cabal, но он попросил проапдейтиться. А cabal update после закачки списка всегда выдает вот такую ошибку:
cabal: user error (Codec.Compression.Zlib: incorrect header check)

Не сталкивались с такой проблемой? В чем может быть причина и соответственно решение?

Добавлю только, что я пытался заюзать его «из коробки» (последнюю Haskell Platform поставил) и дополнительно никак cabal не конфигурировал.
0
steck #
Хм, такой вещи не встречал. Единственное что я делал — раздавал права, чтобы кабал мог писать в соответствующие пути а остальное всё как-то само справлялось. Правда тогда он мне отчетливо писал что не может записать файл.
Может у него какие-то проблемы с получением данных из интернета?
0
GooRoo #
Да вроде не должно быть. Он выкачивает в свою папку файл метров в 14, но распаковать не может :(
0
VoidEx #
Я не знаю, какая версия в Haskell Platform, но делаю всегда так:
cabal update
cabal install cabal-install
После чего делаю cabal update уже для нового :)
Ни разу на проблемы не натыкался.
0
GooRoo #
Фиг его знает. Я бы с удовольствием сделал в таком порядке, но cabal update у меня еще ни разу не завершился успешно. Надо будет под линухом попробовать.
0
GooRoo #
Под линухом, как ожидалось, всё заработало нормально. Начал искать проблему в винде и нашёл: cabal заработал после полного отключения файрволла (хотя, вроде бы правила были настроены, как надо).

Обновил cabal'ом cabal, как Вы и написали :) Спасибо

Непонятно только, почему он в Program Files всё льёт, если у меня Haskell Platform вообще в другом месте. Но это уже другая история…
0
VoidEx #
Ну вот у меня Windows, а проблем не было.
Насчёт Program Files — посмотрите в %USERPROFILE%\AppData\Roaming\Cabal на предмет файла config, там прописаны пути, я их исправляю обычно.
0
GooRoo #
Да, уже разобрался, спасибо!
Оказывается, клёвая это штука… cabal… =)
0
Plague #
Мне лично больше понравилась надстройка над VS2005 — Visua Haskell. Интелисенс, подсветка кода, компиляция — все уже встроено вместе с GHC. :) Установка не требует участия пользователя. :)

К сожалению, исходников нету и пристроить к VS2008 не удалось. :(
+1
shergin #
А давайте переведем всю книгу на translated.by/ благо лицензия это позволяет?
0
folone #
Поддерживаю. К тому же, книжка написана настолько приятно и ненавязчиво, что руки чешутся. Некоторые части, кстати, уже начали переводить.
Только если кто возьмётся, бросьте в меня ссылкой, будьте добры. Я себе на маленький фп-островок копию хочу.
0
folone #
Кстати, человек, который занимается переводом этой книги недавно появился на хабре. Его зовут plague.
0
romx #
«Изучай Haskell ради Бога!»
0
lexich #
Может я задам глупый вопрос… а есть ли привязки к другим языкам?
0
siasia #
C/C++ через FFI. Можно прикрутить и допустим к Python через Python C bindings. Правда я в этом не уверен :)
0
lexich #
Ну официальная дружба с С/С++ радует. Надо будет собраться и выделить время на изучение Haskell. Функциональные языки обладают некоторым изяществом, на первый взгляд
+4
haskel #
Хаскель- моя фамилия, и я всегда бесконечно радуюсь, когда хвалят Haskell.
Я это воспринимаю как комплемент себе :-)
Эм… вот так :-)
0
oogl #
теперь для меня фраза «писать на Хаскеле» звучит как-то по иному ;)
+2
Plague #
Наконец-то разжился инвайтом, добрые люди помогли… :)
Я — начинатель и основной переводчик этой главы книги, т.е. Dmitry Leushin и ищу тех, кто окажет посильную помошь в переводе этой замечательной книги. Глядишь и до Real World Haskell руки дойдут. :)

Сейчас в переводе следующая глава — она переведена начерно, нужна вычитка.
Изучай Haskell ради Добра! Начало

Насчет названия — это первое, что пришло на ум. ;) На самом деле — достаточно точного перевода названия никто не предложил. Были варианты и "… ради Блага"(считаю, что редко используемое слово), и «ради Бога»(при чем тут бог, да и больше на мольбу похоже) и т.п., но более точно передать смысл фразы… вариантов не нашлось. Как я понимаю — там что-то типа "… навсегда!" в положительном ключе, типа «добро/благо навсегда!».
0
siasia #
Я с удовольствием поучаствую.
0
shergin #
Супер! Спасибо тебе! Название классное, оставь его как есть.
А автор выкладывает где-нибудь исходники верстки книжки, чтоб можно было просто перевести только текст, а затем скриптом собрать pdf?
0
Plague #
Перевод я начинал «на пробу для себя». Перевел первую главу, а вторую уже помогли. Начинал перевод весной, но потом отпуск, а после отпуска все как-то некогда, но теперь т.к. вижу, что это кому-то интересно, то продолжу перевод и добавлю на translated.by следующие главы.

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

Ну и на счет перевода первой главы — после отпуска мне кажется, что там есть не мало мест где надо подправить, чтоб «легче» читалось… :)
0
Plague #
Добавлю, в переводе еще мне помогал Etranger :)

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