стек монады с несколькими одинаковыми трансформаторами - PullRequest
0 голосов
/ 11 января 2019

Я пытался написать свои собственные монадные преобразователи, в которых было бы целесообразно иметь несколько одинаковых монадных преобразователей в стеке с разными типами. Вопрос может быть проиллюстрирован монадой читателя.

Монада чтения предлагается как способ удержания контекста только для чтения данного типа

ex1 :: Reader Bool Bool
ex1 = ask

или

ex2 :: Reader Char Bool
ex2 = pure True

монадные трансформаторы допускают менее строгие предположения о подчеркивающей монаде

ex3 :: (MonadReader Bool m) => m Bool
ex3 = ask

однако, что если я хочу иметь более 1 среды только для чтения, я могу написать функцию типа

ex4 :: (MonadReader Bool m, MonadReader Char m) => m Bool
ex4 = ask

Однако, насколько я могу судить, нет способа запустить ex4 с

class Monad m => MonadReader r m | m -> r 

Означает, что каждый MonadReader имеет уникальный тип чтения. Существует ли стандартная обходная схема для нескольких трансформаторов в одном стеке? Должен ли я попытаться избежать этого полностью?

Ответы [ 2 ]

0 голосов
/ 12 января 2019

Используйте трансформатор и лифт, чтобы добраться до вашей внутренней монады:

import Control.Monad.Trans.Reader
import Control.Monad.Trans.Class (lift)

type MyMonad a = ReaderT Bool (Reader Char) a

askBool :: MyMonad Bool
askBool = ask
askChar :: MyMonad Char
askChar = lift ask

Код, который вы представили, не использовал никакого монадного преобразователя (напрямую). Он использовал монаду читателя (которая является преобразователем, применяемым к монаде тождества) и класс типа MonadReader. Как вы заметили, функция типа, подразумеваемая MonadReader, не может привести к двум разным выходам (типам среды) для одного и того же входа (монады m).

0 голосов
/ 11 января 2019

Один из способов справиться с этим относительно простым способом - создать тип, представляющий состояние, за которым вы хотите следить. Скажем, вы хотите отслеживать как Bool, так и Char, как в вашем примере

data MyState = MyState { getBool :: Bool, getChar :: Char }

f :: MonadReader MyState m => m Bool
f = asks getBool

Другие могут иметь более продвинутые решения!

...