Spec-Zone.ru › Haskell 9

6.2.8. Понимания монады

MonadComprehensions
Since:

7.2.1

Включить синтаксис понимания списков для произвольных монад.

Понимания монады обобщают запись понимания списков, включая параллельные понимания (Параллельные понимания списков) и понимания преобразований (Обобщенные (похожие на SQL) понимания списков), чтобы они работали для любой монады.

Понимания монады поддерживают:

  • Связывания:

    [ x + y | x <- Just 1, y <- Just 2 ]
    

    Связывания переводятся с помощью функций (>>=) и return в обычную запись do-нотации:

    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) понимания списков) в пунктах «тогда f» и «тогда сгруппировать с использованием f», когда квалификатор «по b» опущен, аргумент f должен иметь полиморфный тип. В частности, «тогда Data.List.sort» и «тогда сгруппировать с использованием Data.List.group» недостаточно полиморфны.

Понимания монады поддерживают переназначимый синтаксис (Переназначимый синтаксис и неявный импорт Prelude). Без переназначимого синтаксиса операторы из модуля «стандартного связывания» используются; с переназначимым синтаксисом операторы ищутся в текущей лексической области видимости. Например, параллельные понимания будут проверены по типам и отжаты с использованием того, что «mzip» находится в области видимости.

Переназначимые операторы должны иметь «Ожидаемый тип», указанный в таблице выше. Эти типы довольно общие. Например, вы можете использовать оператор связи с типом

(>>=) :: T x y a -> (a -> T y z b) -> T x z b

В случае пониманий преобразования обратите внимание, что группы параметризованы по некоторому произвольному типу n (при условии, что у него есть fmap, а также понимание по произвольной монаде.

© 2002–2007 The University Court of the University of Glasgow. All rights reserved.
Licensed under the Glasgow Haskell Compiler License.
https://downloads.haskell.org/~ghc/9.12.1/docs/users_guide/exts/monad_comprehensions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API