Control.Monad.Trans.Класс
| Авторские права | (c) Andy Gill 2001, (c) Oregon Graduate Institute of Science and Technology, 2001 |
|---|---|
| Лицензия | BSD-стиль (см. файл LICENSE) |
| Поддержка | ross@soi.city.ac.uk |
| Стабильность | экспериментальная |
| Переносимость | переносимая |
| Безопасный Haskell | Безопасный |
| Язык | Haskell98 |
Содержание
Описание
Класс монадических трансформаторов.
Монадический трансформатор создаёт новую монаду из существующей монады, таким образом, что вычисления старой монады могут быть встроены в новую. Для создания монады с желаемым набором функций обычно начинают с базовой монады, такой как Identity, [] или IO, и применяют последовательность монадических трансформаторов.
Класс трансформаторов
class MonadTrans t where Источник
Класс монадических трансформаторов. Экземпляры должны удовлетворять следующим законам, которые утверждают, что lift является трансформацией монады:
Методы
lift :: Monad m => m a -> t m a Источник
Поднимает вычисление из аргументной монады в созданную монаду.
Экземпляры
| MonadTrans IdentityT | |
| MonadTrans ListT | |
| MonadTrans MaybeT | |
| MonadTrans (ContT r) | |
| MonadTrans (ReaderT r) | |
| MonadTrans (StateT s) | |
| MonadTrans (StateT s) | |
| MonadTrans (ExceptT e) | |
| Error e => MonadTrans (ErrorT e) | |
| Monoid w => MonadTrans (WriterT w) | |
| Monoid w => MonadTrans (WriterT w) | |
| Monoid w => MonadTrans (RWST r w s) | |
| Monoid w => MonadTrans (RWST r w s) |
Конвенции
Большинство модулей монадических трансформаторов включают особый случай применения трансформатора к Identity. Например, State s является сокращением для StateT s Identity.
Каждый монадический трансформатор также поставляется с операцией runXXXT для разворачивания трансформатора, предоставляя вычисление внутренней монады. (В настоящее время эти функции определены как метки полей, но в следующей основной версии они будут отдельными функциями.)
Все монадические трансформаторы, кроме ContT, являются функторами на категории монад: помимо определения отображения монад, они также определяют отображение трансформаций между базовыми монадами на трансформации между преобразованными монадами, называемые mapXXXT. Таким образом, заданной монадической трансформацией t :: M a -> N a, комбинатор mapStateT создаёт монадическую трансформацию
mapStateT t :: StateT s M a -> StateT s N a
Каждый из монадических трансформаторов вводит соответствующие операции. В последовательности монадических трансформаторов большинство из этих операций можно поднять через другие трансформаторы с использованием lift или комбинатора mapXXXT, но некоторые с более сложными сигнатурами типов требуют специализированных комбинаторов подъёма, называемых liftOp.
Строгие монады
Монада называется строгой, если её операция >>= является строгой по первому аргументу. Базовые монады Maybe, [] и IO являются строгими:
>>>undefined >> return 2 :: Maybe Integer*** Exception: Prelude.undefined
Однако монада Identity не является таковой:
>>>runIdentity (undefined >> return 2)2
В строгой монаде вы знаете, когда выполняется каждое действие, но монада не обязательно строга в возвращаемом значении или в других компонентах монады, таких как состояние. Однако можно использовать seq для создания действия, строгими по компоненту, который требуется вычислить.
Примеры
Разбор
Можно определить монаду разбора, добавив состояние (String остаток для разбора) к монаде [], которая обеспечивает недетерминизм:
import Control.Monad.Trans.State type Parser = StateT String []
Тогда Parser является экземпляром MonadPlus: монадическая последовательность реализует конкатенацию парсеров, а mplus обеспечивает выбор. Для использования парсеров нужен примитив для запуска созданного парсера на строке ввода:
runParser :: Parser a -> String -> [a] runParser p s = [x | (x, "") <- runStateT p s]
Наконец, нужен примитивный парсер, который сопоставляет один символ, из которого могут быть построены произвольно сложные парсеры:
item :: Parser Char
item = do
c:cs <- get
put cs
return c
В этом примере используются операции get и put из Control.Monad.Trans.State, которые определены только для монад, являющихся приложениями StateT. В качестве альтернативы можно использовать классы монад из пакета mtl или аналогичного, содержащие методы get и put со обобщёнными типами для всех подходящих монад.
Разбор и подсчёт
Можно определить парсер, который также считает, добавив трансформатор WriterT:
import Control.Monad.Trans.Class import Control.Monad.Trans.State import Control.Monad.Trans.Writer import Data.Monoid type Parser = WriterT (Sum Int) (StateT String [])
Функция, которая применяет парсер, теперь должна разворачивать каждый монадический трансформатор по очереди:
runParser :: Parser a -> String -> [(a, Int)] runParser p s = [(x, n) | ((x, Sum n), "") <- runStateT (runWriterT p) s]
Для определения парсера item нужно поднять операции StateT через трансформатор WriterT.
item :: Parser Char
item = do
c:cs <- lift get
lift (put cs)
return c
В этом случае это удалось сделать с помощью lift, но операции с более сложными типами требуют специальных функций подъёма, которые предоставляются монадическими трансформаторами, для которых они могут быть реализованы. Если вы используете классы монад из пакета mtl или аналогичного, этот подъём обрабатывается автоматически экземплярами классов, и вам нужно использовать только обобщённые методы get и put.
Можно также определить примитив с использованием Writer:
tick :: Parser () tick = tell (Sum 1)
Тогда парсер будет отслеживать, сколько tick он выполняет.
Монада интерпретатора
Этот пример является сокращённой версией примера в "Моноидные трансформаторы и модульные интерпретаторы", Sheng Liang, Paul Hudak и Mark Jones в POPL'95 (http://web.cecs.pdx.edu/~mpj/pubs/modinterp.html).
Предположим, что нужно определить интерпретатор, который может выполнять I/O, имеет исключения, среду и изменяемое хранилище. Можно определить монаду, которая поддерживает все эти вещи, как стек монадических трансформаторов:
import Control.Monad.Trans.Class import Control.Monad.Trans.State import qualified Control.Monad.Trans.Reader as R import qualified Control.Monad.Trans.Except as E type InterpM = StateT Store (R.ReaderT Env (E.ExceptT Err []))
для подходящих типов Store, Env и Err.
Теперь нам нужно использовать операции, связанные с каждым из этих монадических трансформаторов, на действиях InterpM. Поскольку верхний монадический трансформатор InterpM является StateT, у него уже есть операции состояния get и set.
Первая из операций ReaderT, ask, — это простое действие, поэтому можно поднять его через StateT в InterpM с помощью lift:
ask :: InterpM Env ask = lift R.ask
Другая операция ReaderT, local, имеет подходящий тип для подъёма с помощью mapStateT:
local :: (Env -> Env) -> InterpM a -> InterpM a local f = mapStateT (R.local f)
Также нужно поднять операции ExceptT через ReaderT и StateT. Для операции throwE известно, что throwE e — это простое действие, поэтому можно поднять его через два монадических трансформатора в InterpM с двумя lift:
throwE :: Err -> InterpM a throwE e = lift (lift (E.throwE e))
Операция catchE имеет более сложный тип, поэтому нам нужно использовать специальную функцию подъёма liftCatch, предоставляемую большинством трансформаторов монады. Здесь мы используем версию ReaderT, за которой следует версия StateT:
catchE :: InterpM a -> (Err -> InterpM a) -> InterpM a catchE = liftCatch (R.liftCatch E.catchE)
Мы могли бы поднять действия IO в InterpM, используя три lift, но InterpM автоматически является экземпляром MonadIO, поэтому мы можем использовать liftIO вместо этого:
putStr :: String -> InterpM () putStr s = liftIO (Prelude.putStr s)
© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/7.10.3/docs/html/libraries/transformers-0.4.2.0/Control-Monad-Trans-Class.html