Ivan Veselov (dying_sphynx) wrote,
Ivan Veselov
dying_sphynx

Categories:

Уроки Typeclassopedia

В хаскелле есть довольно много стандартных классов типов (type classes), ноги у которых растут изо всяких теоретических источников (в основном из теории категорий), например Functor, Monad, Applicative, Arrow и прочие. Чтобы немного в них разобраться, я недавно начал читать отличную статью "Typeclassopedia", написанную Brent Yorgey и опубликованную ещё в тринадцатом номере "The Monad Reader".

Standard type classes

Пока я прочёл небольшую часть статьи, которая описывает такие классы типов:

  • Functor
  • Pointed (его нет в стандартной библиотеке, но он полезен для понимания)
  • Applicative
  • Monad

Раздел о каждом классе состоит из собственно его описания, примеров и части, посвящённой "выработке интуиции". Часть про интуицию, пожалуй, наиболее интересна, но для того, чтобы действительно начать интуитивно понимать суть классов нужно попрактиковаться и, возможно, почитать статьи из подразделов "Further reading". Для практики есть упражнения, в духе "выразить join через return и >>=", весьма уместно размещённые по ходу изложения.

Всякие наблюдения, почёрпнутые из статьи и сопутствующей литературы

1. Follow the types! Весьма полезный совет. Действительно, очень часто можно понять, что происходит, внимательно изучив тип нужной функции. Иногда сама функция выводится практически автоматически, стоит лишь попытаться получить необходимый тип (я таким образом и решил пару упражнений).

2. Четыре вышеприведённых класса отсортированы по "вычислительной мощности": Functor < Pointed < Applicative < Monad. Интересно замечать, чего именно не хватает в предыдущем классе, что появляется в следующем, и для чего это нужно. Довольно важно понимать, что именно нужно от класса и если, к примеру, вычислительной мощности аппликативного функтора достаточно, его иногда удобнее использовать чем монаду (например, об одном из удобств - см. пункт 4).

3. Структура вычислений в аппликативном функторе жёстко задана, в то время как в монаде она может быть гибкой, изменяясь в зависимости от промежуточных результатов. Это (а конкретно: функция (>>=) для связывания вычислений) и есть то, что делает монаду мощнее, чем аппликативный функтор. Под гибкостью монады имеется в виду, что в зависимости от результата промежуточного вычисления может быть выполнено то или иное следующее вычисление. В аппликативном же функторе набор необходимых вычислений для получения результата строго фиксирован и не зависит от промежуточных результатов.

4. Аппликативные функторы и просто функторы хорошо комбинируются друг с другом на уровне композиции типов, то есть если Foo a и Bar a - это функторы, то Foo (Bar a) и Bar (Foo a) - тоже будут функторами. Причём инстанс функтора для этой композиции можно вывести автоматически. У монад так комбинироваться не получается, потому чтобы получить монаду, которая сочетает эффекты двух других монад нужно написать (или использовать имеющийся) трансформер монад, который позволяет наращивать слои дополнительных монад над какой-то базой. Причём не все монады можно теоретически скомбинировать друг с другом, в смысле, что скомбинировать-то можно, но результат уже не будет обладать свойствами монады. Эту часть я вроде бы интуитивно понимаю, но поскольку ещё толком не разобрался с трансформерами, объяснить бы не взялся.

5. Несмотря на то, что каждая монада - это по определению аппликативный функтор, в силу исторических причин в хаскелле класс Monad не имеет никаких ограничений, то есть вместо

class Applicative m => class Monad m where ...

есть просто

сlass Monad m where ...

В связи с этим существуют функции-двойники, которые по сути делают одно и то же, только называются по-разному для функторов и монад. Я имею в виду следующие пары:

  • монадическая liftM и функторная fmap
  • монадическая ap и функторная <*>
  • монадическая return и функторная pure

В общем, статья Typeclasspedia весьма крута, рекомендую! Не знаю, имеет ли много смысла пересказывать в блоге описание классов в своей интерпретации, но я думаю, что мне это будет полезно, поскольку "пока другим рассказал - и сам понял". Может и другим будет интересно. Так что я, наверное, попытаюсь в следующих постах.

Tags: haskell, typeclasses
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 13 comments