2015-10-31 2 views
0

Это contrieved пример использования считывателя Transformer:Получение внутри монады, завернутой в трансформаторе

{-# LANGUAGE UnicodeSyntax #-} 

import Control.Monad.Reader 
import Data.Char 

conv ∷ Int → ReaderT Char Maybe String 
conv n = do 
    yn ← ask 
    if yn == 'y' 
     then return $ chr n : " with Yes" 
     else lift Nothing 

-- runReaderT (conv 98) 'y'  Just "b with Yes" 
-- runReaderT (conv 98) '@'  Nothing 

inspect ∷ ReaderT Char Maybe String → Bool 

- Редакция: согласно предложениям, правильный типа монадический:

inspect ∷ ReaderT Char Maybe String → ReaderT Char Maybe Bool 

inspect предполагается чтобы проверить, является ли значение внутри Nothing. Можно ли это сделать, или у меня «проблемы с дизайном»?

+3

Вы не можете проверить значение без запуска считывателя, так как ответ зависит от значения в окружающей среде. – Lee

+0

Конечно нет. Я предполагал, что «runReaderT проверяет ...» где-то рядом. – punund

+1

что Ли означает, что вы хотите 'проверять :: ReaderT Char Может быть, String -> ReaderT Char Возможно, Bool' - подпись, которую вы дали, в основном может дать только константу (она может кормить' Читателя' своей собственной средой/'Char 'и т.д.) – Carsten

ответ

2

ReaderT точно

newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a } 
     -- a function that reads the environment^ | 
     --       and returns an m a^ 

Для ReaderT r Maybe a это функция, которая считывает среды и возвращает Maybe a. Вы можете создать функцию, которая считывает среду, и проверяет, является ли результат Nothing, составив эту функцию с помощью другой функции, которая проверяет, является ли результат Nothing. Чтобы проверить, не является ли Maybe a, мы можем использовать isJust, и чтобы упаковать полученный результат Bool обратно в Maybe Bool, мы использовали бы return.

inspect :: ReaderT r Maybe a -> ReaderT r Maybe Bool 
inspect (ReaderT f) = ReaderT $ return . isJust . f 

трансформаторы обеспечивают функцию, mapReaderT, что позволяет нам манипулировать вычисление внутри ReaderT

mapReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b 
mapReaderT f m = ReaderT $ f . runReaderT m 

mapReaderT просто сочиняет функцию при условии в качестве первого аргумента с функцией внутри ReaderT (runReaderT разворачивает функцию внутри a ReaderT). Вы можете использовать mapReaderT для более элегантного написания inspect.

inspect :: ReaderT r Maybe a -> ReaderT r Maybe Bool 
inspect = mapReaderT (return . isJust)