2013-05-13 3 views
2

나는 어려운 나를 MonadState을 이해하기 위해 찾을 수 있습니다.레코드 구문을 사용하지 않고 MonadState 클래스를 구현하는 방법은 무엇입니까?

이유는 어쩌면 자신의 데이터 구조에 기록 구문과 함께 혼합 대부분의 예제.

그래서 레코드 구문을 사용하지 않고 MonadState을 구현하려고했습니다.

내가 쓴 다음 코드는 컴파일러를 통과했지만 그것은 나에게 완전히 말도 안되는 것 같습니다.

는이 코드에 어떤 문제가 있습니까?

레코드 구문을 사용하지 않고 MonadState을 구현하는 간단한 예제가 있습니까?

data Foo a b = Foo (Maybe ([a],b)) deriving (Show) 

unwrapFoo :: Foo a b -> Maybe ([a],b) 
unwrapFoo (Foo x) = x 

instance Monad (Foo [a]) where 
    return x = Foo $ Just ([], x) 
    m >>= f = case unwrapFoo m of 
       Just (_, r) -> f r 
       Nothing  -> Foo Nothing 

instance MonadState Int (Foo [a]) where 
    get = Foo $ Just ([], 1)  
    put _ = Foo $ Just ([],()) 


*Main> get :: Foo [a] Int 
Foo (Just ([],1)) 
*Main> put 3 :: Foo [a]() 
Foo (Just ([],())) 
*Main> 
+5

가능합니다. 특정 클래스에 대해 "단지 일부 인스턴스"를 구현하는 방법을 배우는 것은 거의 요지가 없으며 다양한 클래스의 요구 사항에 맞게 데이터 유형을 설계하는 것이 좋습니다. 또는 어떤 문제에 대한 데이터 유형을 설계하고 갑자기 "이봐 요, 이건 '국가'모나드와 같이 행동합니다. 아마도 '모나드 스테이트'의 인스턴스가되어야할까요? - 보통, Monad * 클래스를 위해 그것을 할 필요는 없다. 적당한 변압기 스택을 사용하면된다. – leftaroundabout

+2

'newtype Foo s a = Foo (s -> (s, a))'로 시작하십시오. (-> (S, A)의)'실제로 유형의 함수 '의 래퍼 인 데이터 유형 MonadState을 구현 – dave4420

답변

4

그럼 상태 모나드의 기본 아이디어부터 살펴 보겠습니다.

newtype MyState s a = MyState (s {- current state -} 
          -> (s {- New state -}, a {- New value -})) 

unwrap (MyState f) = f 

그래서 지금 우리는 >>=return를 구현해야합니다.

return은 매우 간단합니다 : 즉

return a = MyState $ \s -> -- Get the new state 
        (s, a) -- and pack it into our value 

, 이것은 단지 새로운 값을 통해 현재 상태를 전달합니다.

그리고 지금 >>=

(MyState f) >>= g = MyState $ \state -> 
    let (newState, val) = f state 
     MyState newF = g val 
    in newF state 

그래서 우리는 g로 결과 값/상태 쌍을 통과, 기존 상태 모나드로 공급하고 그 결과를 반환, 새로운 상태를 가져옵니다. 이 및 기록 구문의 차이의

총 수는 내가 수동으로 unwrap을 정의했다 단지이다.

무슨 잘못 것은 당신이 정말 의미있는`MonadState` 인스턴스를 구현할 수 있도록 국가 FUL 데이터가 여기 입력하지 않아도 우리의 모나드

runState = unwrap 

get = MyState \s -> (s, s) 
put a = MyState \s -> (a,()) 
+0

내가 본 거의 모든 예. 내부 기능을 없앨 수 있습니까? – Znatz

+1

사실, 그건 모나드 모나드와 같습니다. – jozefg

+0

@jozefg 나는 bind에 대한 정의에서'in newF state' 대신에'newF newState'에서해야한다고 생각합니다. – pkaleta