2012-10-23 2 views
6
이 같은 수행하는 리더 모나드를 벗어난 실용적은 Functor을 내가 뭘하고 싶은 것입니다

의 조합 만들기 :를 Reader와 아마 모나드 (실용적은 Functor)

data MyData = Int Int 

get2Sum :: Reader [Int] Int 
get2Sum = do 
    myData <- ask 
    let fst2 = take 2 myData 
    case length fst2 of 
     2 -> return $ sum fst2 
     _ -> return 0 

myDataFromApplicative = MyData <$> get2Sum <*> get2Sum 

main = print $ runReader myDataFromApplicative [1,2] 

그러나을 실행하면 뭔가 같은 내가 원하는 대신 나에게 MyData 0 0

을주는

runReader myDataFromApplicative [1] 

그것은 나에게 Error

을 제공합니다

이 작업을 수행하기 위해 독자적인 독자적인 Monad를 만들면서 놀고 있었지만 실제로 이해할 수는 없었습니다.

은 내가 상상하는 것은 이런 일이 (분명히 이것은 단지 개요

data SuccessReader r a = Interm {runSuccessReader :: r -> SuccessReader a} | Success a | Error 
throwError :: SuccessReader() 


get2Sum :: Reader [Int] Int 
get2Sum = do 
    myData <- ask 
    let fst2 = take 2 myData 
    case length fst2 of 
     2 -> return $ sum fst2 
     _ -> throwError 

myDataFromApplicative = MyData <$> get2Sum <*> get2Sum 

main = do 
    print $ runSuccessReader myDataFromApplicative [1,2] 
    print $ runSuccessReader myDataFromApplicative [1] 

입니다있는 것 출력

Success MyData 3 3 
Error 

답변

8

이 정확히 같이, 자신의 모나드를 작성할 필요가 없습니다 모나드 변압기 및 모나드 스택의 문제 해결 ReaderMaybe의 조합을 원할 경우 Maybe 모나드와 함께 ReaderT 변압기를 사용할 수 있습니다. 예 :

get2Sum :: ReaderT [Int] Maybe Int 
get2Sum = do 
    myData <- ask 
    let fst2 = take 2 myData 
    case length fst2 of 
     2 -> return $ sum fst2 
     _ -> lift Nothing 

get2Sum의 형태는 우리가 내부 모나드 Maybe 포함 외측 모나드 Reader [Int]을 가지고 있다는 것을 의미한다. get2Sum의 구현에서는 lift이 내부 모나드에서 작업을 실행하는 데 사용됩니다 (이 경우 단순히 Nothing로 신호 오류가 발생 함). 실행할 때 이제

Just (MyData 3 3) 
Nothing 

당신은 또한 사용자 정의 newtype

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 

import Control.Applicative 
import Control.Monad.Reader 

data MyData = MyData Int Int deriving Show 

newtype MyMonad a = MyMonad (ReaderT [Int] Maybe a) 
    deriving (Functor, Applicative, Monad, MonadReader [Int]) 

runMyMonad :: MyMonad a -> [Int] -> Maybe a 
runMyMonad (MyMonad m) = runReaderT m 

myError :: MyMonad a 
myError = MyMonad $ lift Nothing 

get2Sum :: MyMonad Int 
get2Sum = do 
    myData <- ask 
    let fst2 = take 2 myData 
    case length fst2 of 
     2 -> return $ sum fst2 
     _ -> myError 

myDataFromApplicative = MyData <$> get2Sum <*> get2Sum 

main = do 
    print $ runMyMonad myDataFromApplicative [1,2] 
    print $ runMyMonad myDataFromApplicative [1] 
내부 모나드 스택을 숨길 수 얻을

main = do 
    print $ runReaderT myDataFromApplicative [1,2] 
    print $ runReaderT myDataFromApplicative [1] 

을 (runReaderTT주의)