2013-03-03 3 views
4

상태 모나드의 세부 사항을 연구하기 위해 간단한 상태 모나드 함수의 완전한 desugared 버전을 만들고, How does 'get' actually /get/ the initial state in Haskell?에서 시작된 생각을 완료하려고합니다. J Cooper의 대답.하스켈 : 간단한 상태 모나드를 desugar하려고 시도하다

예제 상태 모나드 함수는 상태와 입력 값을 단순히 바꿔서 개념적으로 입력이 (v, s)이면 출력이 (s, v)가되도록합니다. 나는 3 가지 번역을 보여줍니다. 처음에는 표기법에서부터 = >>, >> >>에 이르기까지 연산자를 함수 위치에 배치하고 마침내 대체하려고 시도하고 정의를 가져 오거나 넣습니다.

'할'버전과 처음 두 가지 번역이 작동하지만 최종 번역은 작동하지 않습니다. 문제 :

  1. 모듈로드시 GHCi는 z1이 범위에 없다고보고합니다.
  2. 필자는 >> 번역에서 전달되는 인수를 생략하는 것을 정확히 나타내는 방법을 알지 못했습니다.

어떻게 수정해야합니까?

FWIW, 현재 하스켈 플랫폼 (GHC 7.4.2).

감사합니다.

-- simpleswap 

import Control.Monad.State 

-- ============================================= 
-- 'Do' version 
simpleswap1 :: String -> State String String 
simpleswap1 inp = do 
    z1 <- get 
    put inp 
    return z1 

-- ============================================= 
-- Desugared to >>= and >> 
simpleswap2 :: String -> State String String 
simpleswap2 inp = 
    get >>= 
    \z1 -> put inp >> 
    return z1 

-- ============================================= 
-- >>= and >> changed to function position 
simpleswap3 :: String -> State String String 
simpleswap3 inp = 
    (>>=) get 
    (\z1 -> (>>) (put inp) (return z1)) 


-- ============================================= 
-- Attempt to translate >>=, >>, get and put 

simpleswap4 :: String -> State String String 
simpleswap4 inp = 
    state $ \s1 -> 
     -- (>>=) 
     let (a2, s2) = runState ({- get -} state $ \sg -> (sg,sg)) s1 
     in runState (rhs1 a2) s2 
     where 
      rhs1 a2 = \z1 -> 
      -- (>>) 
       state $ \s3 -> 
        let (a4, s4) = runState ({- put inp -} state $ \_ -> (inp,())) s3 
        in runState (rhs2 a4) s4 
        where 
         rhs2 a4 = return z1 

-- ============================================= 
main = do 
    putStrLn "version 1004" 
    let v = "vvv" 
    let s = "sss" 
    putStrLn ("Before val: " ++ v ++ " state: " ++ s)  
    let (v2, s2) = runState (simpleswap4 v) s 
    putStrLn ("After val: " ++ v2 ++ " state: " ++ s2) 

-- ============================================= 

답변

2

simpleswap4에는 몇 가지 사소한 실수가 있습니다. 다음은 수정 된 버전입니다 : 내가 a2z1로 이름을 변경 한

simpleswap4 :: String -> State String String 
simpleswap4 inp = 
    state $ \s1 -> 
     -- (>>=) 
     let (z1, s2) = runState ({- get -} state $ \sg -> (sg,sg)) s1 
     in runState (rhs1 z1) s2 
     where 
      rhs1 z1 = 
      -- (>>) 
       state $ \s3 -> 
        let (_, s4) = runState ({- put inp -} state $ \_ -> ((), inp)) s3 
        in runState rhs2 s4 
        where 
         rhs2 = return z1 

(라인 5, 6). 이것은 의미를 변경하지 않지만, get 호출에 의해 반환 된 쌍의 첫 번째 구성 요소는 실제로 이전 버전의 simpleswap에서 z1에 바인딩되는 결과라는 점을 강조했습니다.

rhs1 유형은 String -> State String String이어야합니다. 귀하의 버전에서는 추가 람다 바운드 변수를 얻습니다. a2z1의 차이점을 사용자 버전에 반영해야할지 확실하지 않습니다. 람다를 제거하면 (8 번 줄) 범위 지정 문제를 해결할 수있는 이점이 있습니다. 중첩 된 where 절에 z1을 사용하고 있지만 where은 첨부 된 선언의 왼쪽에 바인딩 된 변수 만 볼 수 있습니다.

11 번 줄에서 a4_으로 바꿨습니다. 이는 (>>)이 첫 번째 작업의 결과를 삭제한다는 것을 강조하기위한 것입니다. 결과적으로 rhs2은이 결과에 대해서도 매개 변수화되지 않습니다.

+0

굉장! 내 시도를 수정하고 변경 사항을 자세히 설명해 주셔서 대단히 감사합니다. 매우 감사! – gwideman