Почему для последовательности требуется монада, если достаточно аппликативной?

Подпись последовательности

sequence :: Monad m => t (m a) -> m (t a)

Но мы можем реализовать это как

sequence = traverse id

требуя, чтобы m было просто Applicative. Если монады являются аппликативными, то зачем заморачиваться этим ограничением на уровне типа?

Исторические причины. Для современного хаскеллиста есть sequenceA.

luqui 03.04.2019 05:43

Более конкретно: он был определен до того, как Applicative стало известно, а позже был сохранен, потому что, когда Applicative был добавлен к base, он еще не был надклассом Monad.

Alexey Romanov 03.04.2019 07:08

По какой-то причине некоторые функции в прошлом были обобщены до foldables/traversables, когда они были введены, но предыдущие функции, связанные с монадами (ap, sequence, ...), сохраняли свой тип даже при введении аппликативов. Такие изменения не являются обратно совместимыми, это правда, но другие обобщения также не являются обратно совместимыми, поэтому я не уверен в исторической причине. (Haskell сильно изменился: например, в прошлом Monad даже не был подклассом Functor)

chi 03.04.2019 13:52

@chi Если [] был дан экземпляр Foldable, когда foldr был обобщен до (a -> b -> b) -> b -> t a -> b, это не совсем несовместимое изменение, не так ли? Когда был введен Applicative, монады не сразу стали аппликативами. Теперь, когда Applicativeявляется является надклассом Monad, sequence, вероятно, можно было бы перепечатать. (Тем не менее, какой угловой случай мне не хватает?)

chepner 03.04.2019 13:59

@chepner Это все равно несовместимо, в общем случае, к сожалению. Например, если class C a where foo :: a с instance C [a] where foo = [], то length foo компилируется, если length заставляет [a], но если length требует только складной код, код неоднозначен. (В GHCi это работает только из-за ExtendedDefaultRules) Это надуманный пример, но подобные неясности могут возникать в реальном коде.

chi 03.04.2019 14:07

Я считаю, но не могу найти ссылку прямо сейчас, что есть определенные (квази-надуманные? полностью надуманные?) примеры, где sequence может быть быстрее, чем sequenceA. Если кто-нибудь сможет найти это объяснение (может быть, благодаря Эдварду Кметту?), Я думаю, это будет отличный ответ.

Antal Spector-Zabusky 03.04.2019 21:35

Связано: что означает A в sequenceA?

duplode 03.04.2019 23:52
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
7
252
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В Haskell есть много функций, которые эквивалентны, но различны, потому что Applicative (соответственно Functor) не был суперклассом Monad. Например:

  • return против pure

  • ap против <*>

  • liftM против liftA против fmap

  • liftM2, liftM3 и т. д. по сравнению с liftA2, liftA3 и т. д.

  • mapM/forM против traverse/for

  • mapM_/forM_ против traverse_/for_

  • sequence против sequenceA

  • mzero и mplus (из MonadPlus) против empty и <|> (из Alternative)

Старые функции с их оригинальными Monad сигнатурами все еще присутствуют, но в новом коде, поскольку был реализован Аппликативно-монадное предложение (AMP), вы всегда можете использовать версии Applicative, потому что они немного более общие, то есть вы всегда можете заменить return на pure, но не наоборот.

Не могли бы вы уточнить «причины совместимости»? В частности, что сломается, если сегодня sequence изменить, например, на подпись типа sequenceA?

Joseph Sible-Reinstate Monica 05.04.2019 03:02

@JosephSible: Вы знаете, я могу ошибаться — ничто должен не сломается только из-за изменения подписи, и на самом деле может быть план сделать это в будущем. Это были другие изменения, которые не вошли в AMP, такие как перемещение join внутрь Monad и удаление return, iirc из-за проблем с ролевой системой.

Jon Purdy 06.04.2019 23:51

Другие вопросы по теме