learnhaskell/specific_topics-ua.md

29 KiB
Raw Blame History

Конкретны теми для користувачів Haskell

Що роблять синтаксичні конструкції <- / do / спискове включення?

Чудова стаття розглядає ці питання.

Щоб зрозуміти списки та згортання списків (fold)

Щоб вивчити деякі відомі класи типів

Матеріал, що дуже корисний для розуміння Functor, Applicative, Monad, Monoid та інших класів типів в цілому, а також трохи специіфчної для Haskell теорії категорій.

Розуміння базових повідомлень про помилки від Haskell


Лінивість, строгість, стримана рекурсія

Маленька демонстрація

let a = 1 : a -- guarded recursion, (:) is lazy and can be pattern matched.
let (v : _) = a
> v
1
> head a -- head a == v
1

let a = 1 * a -- not guarded, (*) is strict
> a
*** Exception: <<loop>>

IO

Коментар з обговорення в Reddit від glaebhoerl

Цікаве зауваження: GHC мусить приховувати представлення токену стану за абстрактним типом IO через те, що токен стану завжду мусть використовуватись лінейно (не дублюватись або бути скинутим), але система типів не може примушувати до цього. Інша Haskell-подібна мова під назвою Clean має систему унікальних типів (які подібні до лінейних типів і, можливо, інші в аспектах, які я не знаю), і вони надають можливість прямої передачі World, маючи (не абстрактну) монаду 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, Functor, Applicative!

Самотужки реалізуйте бібліотечні монади (List, Maybe, Cont, Error, Reader, Writer, State) для того, щоб зрозуміти їх краще. Тоді, наприклад, напишіть монадний інтерпретатор невеликої мови виразів за допомогою Monad Transformers Step by Step (згадується також нижче, у розділі 'транфсормери монад').

Написання декількох інтерпретаторів простою зміною монад для зміни семантики може надати додаткового розуміння про те, що відбувається.

Також заново реалізуйте Control.Monad. Функціїї накшталт mapM чи sequence є чудовою можливістю набути практики з написання узагаленного монадічного коду.

У якості путівника можна також використати курс Data61, частиною якого також є написання власної реалізації Applicative.

Автори:

  • Коментар на Reddit від htmltyp та Crandom here.

  • Комментар на Reddit від jozefg here.

Трансформари монад

Тестування, тести, специфікації, тестування властивостей та генеративне

  • Фантастичний посібник від Kazu Yamamoto.

  • Simple-Conduit: Гарна маленька бібліотека, яка допомогає зрозуміти, як загалом працює потоковий IO. Це знання можна відобразити на бібліотеки типу Pipes та Conduit.

Парсинг у Haskell

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

Aeson - стандартне рішення для парсингу JSON в Haskell. Цей пакет доступний на hackage та github.

Структури даних та алгоритми для роботи з графами

Середовище розробки

Emacs

Vim

Sublime Text

Робота із Cabal

Принципи роботи з Cabal

До того, як з'явились так звані сендбокси, користувачі Haskell стикались з проблемою, відомою як Cabal Hell. Встановлення пакетів поза сендбоксом призведе до реєстрації його у базі package-db, що є глобальною для користувача, і зазвичай це не дуже гарна ідея. Виключенням є лише найбазовіші пакети накшталт Cabal, alex, happy. Нічого іншого не мусить встановлюватись у package-db глобальний для системи або користувача окрім випадків, коли ви дійсно знаєте, що робите.

Поради як запобігти потраплянню в Cabal Hell, можна прочитати тут.

Для того, щоб поекспериментувати із пакетом, або розпочати новий проект, почніть зі створення сендбоксу у новій директорії: cabal sandbox init.

Якщо коротко:

  • Завжди використовуйте сендбокси для інсталяції нових пакетів, збирання нових або існуючих проектів, або ж для експериментів.

  • Для запуску інтерпретатору GHC у контексті проекту, завжди використовуйте cabal repl.

Рекомендований тут підхід, що базується на використанні сендбоксів, призначений допомогти обійти проблеми із залежностями, але він не сумісний із тим, як Haskell Platform надає готові пакунки. Якщо ви ще тільки вивчаєте Haskell і не розумієте, як працють ghc-pkg and Cabal, уникайте platform і замість того використовуйте підхід, що описано раніше в цьому посібнику.

Stackage

Усі користувачі, в яких є проблеми з білдами (зазвичай це користувачі Yesod), мають можливість обміркувати використання Stackage.

  • Непоганий огляд Stackage можна знайти тут.

Автор вважає, що Stackage, зазвичай, більш корисний, ніж cabal freeze.

Hoogle and Haddock

Шукайте код за сигнатурою типів

Пошуковий сервіс Hoogle вміє шукати за типом.

Наприклад, подивіться на результати пошуку за виразом (a -> b) -> [a] -> [b] тут.

Ще одне дзеркало на fpcomplete.

Ще є Hayoo (який для пошуку за замовченням використовує увесь зміст hackage).

Налаштування власної локальної копії Hoogle

Описано тут.

Haddock

  1. Fix your hackage documentation

  2. Hackage documentation v2

Зауваження: обидві статті трошки застаріли: наприклад, зараз Hackage також показує новесеньку інформацію стосовно статусу білда і документації.

Що дійсно треба знати

Для того, щоб haddocks містив документацію і з пакунків, які стосуються вашого проекту, треба додати documentation: True до вашого ~/.cabal/config. Якщо було використане значення за замовчуванням (False) або False було встановлене вручну, то перед генерацією haddocks необхідно буде видалити всі ваші пакунки і заново переінсталювати їх.

Треба пам'ятати ще одну річ: через те, що Cabal, а не ви, інтерпретує параметр $pkg, тому параметри html-location та content-location мусять бути записані у одинарник лапках і введені в командний інтерпретатор або записані у скрипті інтерпретатора. Вони не будуть працювати у Makefile через те, що вони будуть інтерпретовані як змінні Make!

#! /usr/bin/env sh

# Цю команду можна записати в один рядок, але тоді приберіть слеші
cabal haddock --hoogle --hyperlink-source                       \
 --html-location='http://hackage.haskell.org/package/$pkg/docs' \
 --contents-location='http://hackage.haskell.org/package/$pkg'

TravisCI

Якщо ви є великим шанувальником TravisCI, тоді дуже рекомендується подивитись на multi-ghc-travis як на базовий приклад travis.yml для ваших Haskell-проектів.

Frontend/JavaScript

Тут в нас є просто безліч різноманітних варіантів. Ось три базові рекомендації:

Яку мову використовувати для фронтенду

І GHCJS, і Haste є повноцінною реалізацією Haskell. Під GHCJS будуть працювати більше Haskell проектів, ніж із Haste, але це не дуже впливає на розробку фронтенд-проектів. Purescript - це зовсім не Haskell і тому використовувати код із бекенду напряму не вийде.

GHCJS має найбільший розмір допоміжних бібліотек, необхідних для його работи, який сягає 100Кб (luite працює над цією проблемою). Haste та PureScript більш-менш однакові.

Інтеграція із інтструментарем JS найкраща в PureScript (використовується gulp/grunt/bower), в той час як у GHCJS та Haste краще працює із інструментами Haskell (Cabal).

Усі три - чудовий вибір і підходять для більшості фронтендових проектів.

Для більш повного розуміння лінивості NF, WHNF

Дослідницькі папери про ліниве лямбда-числення

Паралелізм/конкарренсі

  • Parallel and Concurrent Programming in Haskell. Ця книга за авторством Саймона Мерлоу (Simon Marlow) є, мабуть, однією із найкращих книг про паралелізм та конкаренсі

  • Ґрунтовний посібник стосовно тестування та інкрементальної розробки багатопотокових програм на Haskell.

  • Functional Reactive Programming

Lenses та Prisms

Після того, як ви набудете певності у роботі із Haskell, поставьтесь серйозно до вивчення Lenses та Prisms, навіть якщо ви просто "користувач". Для того, щоб вони стали вам у нагоді, не треба розуміти базові для них категорії.

Люди з легкістю переоцінюють складність використання Lens. Будь-хто із достатнім розумінням Functor/Foldable/Traversable (або навіть лише Functor) може використати лінзи та призми для того, щоб зробити своє життя трішечки краще.

Якщо коли небудь ви писали щось типу (fmap . fmap), ви подумки використовували лінзи.

Ці дві статті є рекомендованим введенням в тему:

Для подальшої інформації звертайтесь сюда: Lens package on hackage.

Схеми рекурсії

Деякі божевільні *-morphism слова, які ви зустрічали, насправді говорять про рекурсію. Зауважте: перед тим, як переходити до цього матеріалу, треба розуміти, як реалізувати foldr для списків і хочаб ще однієї структури даних, наприклад для дерев (fold - це катаморфізм). Розуміння реалізації unfold (анаморфізм) для тих же структур ще більше полегшить вивчення теми.

Цей матеріал пов'язує між собою traversable та foldable.

GHC Core та оптимізація швидкості виконання

Типи та теорія категорій

НЕ ПОТРІБНА для того, щоб просто писати на Haskell. Просто для тих, хто цікавиться.

Якщо ви маєте час та натхнення набути розуміння типів та теорії категорій:

Книги

Інші веселі теми

Параметричність, ad-hoc та параметричний поліморфізм polymorphism, вільні теореми

Initial та Final, DSL, Finally Tagless

Комонади

Yoneda / CoYoneda

Propositions vs. Judgments (обчислення)

Залежная типізація

Статичная лінковка бінарників