2013-03-03 15 views
4

爲了研究國家monad的細節,我試圖創建一個簡單的狀態monad函數的完全desugared版本,完成在How does 'get' actually /get/ the initial state in Haskell?開始的想法,在J Cooper回答。哈斯克爾:試圖desugar簡單的國家monad得到並把

示例狀態monad函數簡單地交換狀態和輸入值,所以(概念上)如果輸入是(v,s),那麼輸出是(s,v)。我展示了三種翻譯,第一種是從符號到desugared >> =和>>,然後將這些操作符置於函數位置,最後嘗試替換它們並獲取/放入它們的定義。

'做'版本和前兩個翻譯工作,但最後的翻譯沒有。問題:

  1. 加載模塊後,GHCi報告z1不在範圍內。
  2. 我還沒有想出如何表示省略在翻譯中傳遞的參數。

這些問題應該如何解決?

FWIW,現在的Haskell平臺(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有一些小錯誤。這裏是一個修正版本:

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 

我改名a2z1(以線5和6)。這並不會改變語義,但強調由desugared get調用返回的對的第一個組件實際上是在simpleswap的以前版本中綁定到z1的結果。

rhs1的類型應該是String -> State String String。在你的版本中,它會得到一個額外的lambda綁定變量。目前還不清楚a2z1應該在您的版本之間的區別。刪除lambda(在第8行)也有解決您的範圍問題的優勢。您在嵌套的where條款中使用z1,但where只能看到綁定在其聲明左側的變量。

在第11行中,我用_代替a4。這是爲了強調(>>)確實放棄了第一個操作的結果。因此,rhs2也未通過此結果參數化。

+0

太棒了!非常感謝您糾正我的嘗試,並詳細說明這些更改。非常感激! – gwideman 2013-03-03 11:24:53