Если вам интересно, вот некоторые мысли неэксперта
о роли монад и приставок в языках программирования:
Прежде всего, существует для данной монады T
уникальное присоединение к категории Клейсли T
.
В Haskell использование монад в основном сводится к операциям в этой категории.
(которая по сути является категорией свободных алгебр, без факторов).
Фактически, все, что можно сделать с монадой на Хаскеле, - это составить некоторые морфизмы Клейсли:
введите a->T b
с помощью выражений do, (>>=)
и т. д., чтобы создать новый
морфизм. В этом контексте роль монад ограничивается только экономикой
нотации. Один из них использует ассоциативность морфизмов для записи (скажем) [0,1,2]
вместо (Cons 0 (Cons 1 (Cons 2 Nil)))
, то есть вы можете написать последовательность как последовательность,
не как дерево.
Даже использование монад IO не является обязательным, поскольку нынешняя система типов Haskell является мощной
достаточно для реализации инкапсуляции данных (экзистенциальные типы).
Это мой ответ на ваш оригинальный вопрос,
но мне любопытно, что эксперты по Haskell говорят по этому поводу.
С другой стороны, как мы уже отмечали, существует также соответствие 1-1 между монадами и
присоединения к (T-) алгебрам. Адъюнкты, с точки зрения Маклейна, - это «путь
чтобы выразить эквивалентность категорий.
В типичной установке примыканий <F,G>:X->A
, где F
- это своего рода
'генератора свободной алгебры' и G 'функтора забвения', соответствующей монаде
(посредством использования T-алгебр) опишет, как (и когда) алгебраическая структура A
строится на объектах X
.
В случае Hask и монады T списка, структура, которую вводит T
, такова, что
моноида, и это может помочь нам установить свойства (в том числе правильность) кода с помощью алгебраического
методы, которые обеспечивает теория моноидов. Например, функция foldr (*) e::[a]->a
может
легко увидеть как ассоциативную операцию, пока <a,(*),e>
является моноидом,
факт, который может быть использован компилятором для оптимизации вычислений (например, параллелизмом).
Другое приложение состоит в том, чтобы идентифицировать и классифицировать «шаблоны рекурсии» в функциональном программировании, используя категориальные
методы в надежде (частично) избавиться от «перехода к функциональному программированию», Y (произвольный рекурсивный комбинатор).
Видимо, такого рода приложения являются одной из основных мотиваций создателей теории категорий (Маклейн, Эйленберг и т. Д.),
а именно, установить естественную эквивалентность категорий и перенести известный метод в одну категорию
к другому (например, гомологические методы к топологическим пространствам, алгебраические методы к программированию и т. д.).
Здесь примыкания и монады являются незаменимыми инструментами для использования этой связи категорий.
(Между прочим, понятие монад (и их двойственных, комонад) является настолько общим, что можно даже пойти так далеко, чтобы определить «когомологии»
Типы на Haskell. Но я еще не подумал.)
Что касается недетерминированных функций, о которых вы упоминали, я могу сказать гораздо меньше ...
Но учтите это; если присоединение <F,G>:Hask->A
для некоторой категории A
определяет монаду списка T
,
должен быть уникальный «функтор сравнения» K:A->MonHask
(категория моноидов, определяемая в Haskell), см. CWM.
По сути, это означает, что ваша интересующая категория должна быть категорией моноидов в некоторой ограниченной форме (например, в ней могут отсутствовать некоторые частные, но не свободные алгебры) для определения монады списка.
Наконец, несколько замечаний:
Функтор бинарного дерева, о котором я упоминал в своей последней публикации, легко обобщается на произвольный тип данных
T a1 .. an = T1 T11 .. T1m | ...
.
А именно, любой тип данных в Haskell, естественно, определяет монаду (вместе с соответствующей категорией алгебр и категорией Клейсли),
что является просто результатом того, что любой конструктор данных в Haskell является тотальным.
Это еще одна причина, почему я считаю, что класс Monad в Haskell не намного больше, чем синтаксический сахар
(что очень важно на практике, конечно).