-
MonadComprehensions -
- Зависит от:
- Начиная с версии:
-
7.2.1
Включает синтаксис выражений-генераторов списков для произвольных монад.
Монадические выражения-генераторы обобщают нотацию выражений-генераторов списков, включая параллельные выражения-генераторы (Параллельные выражения-генераторы списков) и выражения-генераторы с преобразованиями (Обобщённые выражения-генераторы списков (в стиле SQL)), для работы с любой монадой.
Монадические выражения-генераторы поддерживают:
-
Связывания:
[ x + y | x <- Just 1, y <- Just 2 ]
Связывания преобразуются в обычную do-нотацию с помощью функций
(>>=)иreturn:do x <- Just 1 y <- Just 2 return (x+y)
-
Условия:
[ x | x <- [1..10], x <= 5 ]
Условия преобразуются с помощью функции
guard, для которой требуется экземплярAlternative:do x <- [1..10] guard (x <= 5) return x
-
Операторы преобразования (как и в
TransformListComp):[ x+y | x <- [1..10], y <- [1..x], then take 2 ]
Это преобразуется в:
do (x,y) <- take 2 (do x <- [1..10] y <- [1..x] return (x,y)) return (x+y) -
Операторы группировки (как и в
TransformListComp):[ x | x <- [1,1,2,2,3], then group by x using GHC.Exts.groupWith ] [ x | x <- [1,1,2,2,3], then group using myGroup ]
-
Параллельные операторы (как и в
ParallelListComp):[ (x+y) | x <- [1..10] | y <- [11..20] ]Параллельные операторы преобразуются с помощью функции
mzip, для которой требуется экземплярMonadZip, определённый в Control.Monad.Zip:do (x,y) <- mzip (do x <- [1..10] return x) (do y <- [11..20] return y) return (x+y)
Все эти возможности включаются по умолчанию, если включено расширение MonadComprehensions. Типы и более подробные примеры использования выражений-генераторов приведены в предыдущих главах: Обобщённые выражения-генераторы списков (в стиле SQL) и Параллельные выражения-генераторы списков. Как правило, для монадических выражений-генераторов достаточно заменить тип [a] на тип Monad m => m a.
Примечание
Хотя в большинстве этих примеров используется монада списка, монадические выражения-генераторы работают с любой монадой. Пакет base предоставляет все необходимые экземпляры для списков, благодаря чему MonadComprehensions обратно совместимо со встроенными, преобразующими и параллельными выражениями-генераторами списков.
Более формально, десахаризация выполняется следующим образом. Обозначим D[ e | Q] десахаризацию монадического выражения-генератора [ e | Q]:
Expressions: e
Declarations: d
Lists of qualifiers: Q,R,S
-- Basic forms
D[ e | ] = return e
D[ e | p <- e, Q ] = e >>= \p -> D[ e | Q ]
D[ e | e, Q ] = guard e >> \p -> D[ e | Q ]
D[ e | let d, Q ] = let d in D[ e | Q ]
-- Parallel comprehensions (iterate for multiple parallel branches)
D[ e | (Q | R), S ] = mzip D[ Qv | Q ] D[ Rv | R ] >>= \(Qv,Rv) -> D[ e | S ]
-- Transform comprehensions
D[ e | Q then f, R ] = f D[ Qv | Q ] >>= \Qv -> D[ e | R ]
D[ e | Q then f by b, R ] = f (\Qv -> b) D[ Qv | Q ] >>= \Qv -> D[ e | R ]
D[ e | Q then group using f, R ] = f D[ Qv | Q ] >>= \ys ->
case (fmap selQv1 ys, ..., fmap selQvn ys) of
Qv -> D[ e | R ]
D[ e | Q then group by b using f, R ] = f (\Qv -> b) D[ Qv | Q ] >>= \ys ->
case (fmap selQv1 ys, ..., fmap selQvn ys) of
Qv -> D[ e | R ]
where Qv is the tuple of variables bound by Q (and used subsequently)
selQvi is a selector mapping Qv to the ith component of Qv
Operator Standard binding Expected type
--------------------------------------------------------------------
return GHC.Base t1 -> m t2
(>>=) GHC.Base m1 t1 -> (t2 -> m2 t3) -> m3 t3
(>>) GHC.Base m1 t1 -> m2 t2 -> m3 t3
guard Control.Monad t1 -> m t2
fmap GHC.Base forall a b. (a->b) -> n a -> n b
mzip Control.Monad.Zip forall a b. m a -> m b -> m (a,b)
Выражение-генератор должно проходить проверку типов, если её проходит его десахаризованная форма, за исключением следующего: как обсуждается в главе Обобщённые выражения-генераторы списков (в стиле SQL), в предложениях «then f» и «then group using f», если квалификатор «by b» опущен, аргумент f должен иметь полиморфный тип. В частности, «then Data.List.sort» и «then group using Data.List.group» недостаточно полиморфны.
Монадические выражения-генераторы поддерживают повторно связываемый синтаксис (Повторно связываемый синтаксис и неявный импорт Prelude). Без повторно связываемого синтаксиса используются операторы из модуля «стандартного связывания»; при его наличии операторы ищутся в текущей лексической области видимости. Например, параллельные выражения-генераторы будут проверяться на соответствие типам и десахаризоваться с использованием того оператора «mzip», который находится в области видимости.
Повторно связываемые операторы должны иметь «ожидаемый тип», указанный в таблице выше. Эти типы на удивление общие. Например, можно использовать оператор связывания с типом
(>>=) :: T x y a -> (a -> T y z b) -> T x z b
В случае выражений-генераторов с преобразованиями обратите внимание: группы параметризованы некоторым произвольным типом n (при условии, что у него есть fmap), а само выражение-генератор может работать с произвольной монадой.