Как стать автором
Обновить

Комментарии 12

> Монада — функтор

Разве?

Похоже на то. В cats:


trait Monad[F[_]] extends Applicative[F]
trait Applicative[F[_]] extends Apply[F]
trait Apply[F[_]] extends Functor[F]

В scalaz похожая ситуация.

Функтор — метод map. Монада — методы point и bind. Имея point и bind метод map можно получить тривиальным образом (см третью с конца строку в ответе).
монада — это моноид в категории эндофункторов. У него помимо бинарной операции, конечно, есть целое множество функторов, и из монады даже можно выделить один особенный, выполняющий роль единицы.

Но это всё равно что сказать, что автомобиль является (расширяет) ДВС. Несомненно, в типичном автомобиле есть двигатель и ровно один. И все методы двигателя могут быть делегированы автомобилем, его несущим. Но ведь автомобиль от этого не становится двигателем.

Насколько я понимаю, в данном случае функтор, который конструируется из монады — единственный. Морфизм f: A=>B конвертируется в M[A] => M[B] путём использования двух операций, предоставляемых монадой. Вначале функцию f превращаем в вычисление, применяя нулевое вычисление η к результату функции: φ = λa.ηfa, а затем конструируем результирующую функцию в lifted-категории с использованием моноидного умножения μ: λma.μma φ.
В Scala это выглядит, как привычный способ выразить map через flatMap и pure:


def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
def pure[A](x: A): F[A]
def map[A, B](fa: F[A])(f: A => B): F[B] = flatMap(fa)(a => pure(f(a)))

Эндофункторов, над которыми строится моноид, действительно много, но ни один из них, насколько я могу судить, не имеет такой формы, как этот — (A=>B) => (M[A] => M[B]).

Вы с точки зрения программирования или теории категорий?

Я рассматриваю монаду с точки зрения программирования. В статье Monads for functional programming (Philip Wadler) монада определяется как тройка, состоящая из конструктора типа, отображения, превращающего обычное значение в этот тип ("нулевое" вычисление), и отображения, связывающего два вычисления в одно.
То, что монада также является функтором, следует из того, что монада (как и функтор) позволяет преобразовать простые функции над базовыми типами в lifted-функции над сконструированным типом, то есть позволяет выполнить отображение категории обычных функции в категорию lifted-функций.
Несмотря на это, монада — более универсальная конструкция, чем функтор. Монада не только отображает обычные функции в lifted, но и предоставляет дополнительные возможности работы с функциями типа A => M[B], которые включают конструируемый тип — "вычислениями". При этом, сам конструируемый тип M[B] оказывается включен в класс объектов категории (поэтому, по-видимому, категория эндофункторов; при этом конструктор типа M[?] не включен в объекты категории). И вместо двух изолированных категорий, связанных функтором, мы оперируем одной категорией, в структуре которой выделены функции особого вида — вычисления, — и объекты — M[B], инкапсулирующие (потенциальный) результат вычисления. Для этих функций/вычислений монада предоставляет базовый набор действий, соответствующий моноиду, — нулевое действие (без вычислений), и комбинирование двух вычислений.

Так с вами-то я и не спорил. Все так и есть.
Конечно. Монада — функтор и два естественных преобразования (natural transformations)
Так как данные не могут произвольно меняться, то нет причины их скрывать, и вместо сокрытия данных теперь используются открытые типы, где данные — публичны. (Тем самым, среди трёх столпов ООП — полиморфизма, наследования и инкапсуляции, — один оказывается несколько задвинут в сторону.)

Вы путаете инкапсуляцию и сокрытие. Модификатор private на данных — это слишком мелко для такого важного столпа как инкапсуляция.

Да, вы правы. Сокрытие и инкапсуляция хоть и идут рука об руку во многих языках, всё-таки концептуально отличаются. Неизменяемые типы данных сами по себе не исключают инкапсуляцию, а лишь подрывают рациональные основания для сокрытия данных.


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

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


Правда?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории