4

State モナドの詳細を調べるために、単純な状態モナド関数の完全な desugar バージョンを自分で作成して、Haskell で「get」は実際に初期状態を /get/ する方法は?で始まった考えを完成させようとしています。、J Cooperによる回答。

状態モナド関数の例では、(概念的に) 入力が (v, s) の場合、出力は (s, v) になるように、状態と入力値を単純に交換します。3 つの変換を示します。最初は do 表記から desugared >>= および >> へ、次にこれらの演算子を関数の位置に配置し、最後にそれらを置き換えて get/put をそれらの定義で試みます。

「do」バージョンと最初の 2 つの翻訳は機能しますが、最終的な翻訳は機能しません。問題:

  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)

-- =============================================
4

1 に答える 1

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

名前を変更a2しましたz1(5行目と6行目)。これはセマンティクスを変更しませんが、脱糖されたget呼び出しによって返されるペアの最初のコンポーネントは、実際にz1は以前のバージョンのにバインドされた結果であることを強調しましたsimpleswap

のタイプはであるrhs1必要がありますString -> State String String。お使いのバージョンでは、追加のラムダ結合変数を取得します。あなたのバージョンのa2との違いは不明です。z1ラムダを削除すると(8行目)、スコープの問題を修正できるという利点もあります。z1ネストされた句で使用していwhereますが、whereは、アタッチされている宣言の左側にバインドされている変数のみを表示できます。

11行目で、に置き換えa4ました_(>>)これは、最初のアクションの結果を破棄することを強調するためです。結果として、rhs2この結果に対してもパラメータ化されません。

于 2013-03-03T10:14:13.940 に答える