IO モナドと一緒に AppState を構築するために、状態と IO アクションを組み合わせるで与えられたアドバイスに従おうとしています。私が得たのはこれです:
module Main where
import Control.Monad.State
import Control.Monad.Trans
data ST = ST [Integer] deriving (Show)
type AppState = StateT ST IO
new = ST []
append :: Integer -> State ST ()
append v = state $ \(ST lst) -> ((), ST (lst ++ [v]))
sumST :: State ST Integer
sumST = state $ \(ST lst) -> (sum lst, ST lst)
script = do
append 5
append 10
append 15
sumST
myMain :: AppState ()
myMain = do
liftIO $ putStrLn "myMain start"
let (res, st) = runState script new
liftIO $ putStrLn $ show res
liftIO $ putStrLn "myMain stop"
main = runStateT myMain (ST [15])
これのいくつかの部分が得られていません。script
私がとmyMain
と を持っていることは非常に気になりmain
ます。runState
また、内部で実行する必要があり、メイン関数にmyMain
初期状態をフィードする必要があることも気になります。runStateT
myMain の全体的なポイントは、追加と合計を myMain で直接、印刷操作のすぐ隣で実行できるようにすることであるため、いわば「スクリプト」を myMain 関数で直接使用したいと考えています。代わりに、これを行うことができるはずだと思います:
myMain :: AppState ()
myMain = do
liftIO $ putStrLn "myMain start"
append 5
append 10
append 15
r <- sumST
liftIO $ putStrLn $ show res
liftIO $ putStrLn "myMain stop"
main = runState myMain
モナドトランスフォーマーのポイントは、State モナド操作を関数 (上記のように) で実行し、IO 操作をその関数に持ち上げることだと考えていました。間接的なレイヤーの 1 つを削除できるように、これらすべてを設定する正しい方法は何ですか?
ダニエルの解決策 (私は解決策にフラグを立てました) に加えて、状況に光を当てる可能性のあるいくつかのバリエーションも見つけました。まず、myMain と main の最終的な実装:
myMain :: AppState ()
myMain = do
liftIO $ putStrLn "myMain start"
append 5
append 10
append 15
res <- sumST
liftIO $ putStrLn $ show res
liftIO $ putStrLn "myMain stop"
main = runStateT myMain new
現在、ダニエルの実装に加えて、append と sumST のさまざまな実装:
append :: Integer -> AppState ()
append v = state $ \(ST lst) -> ((), ST (lst ++ [v]))
sumST :: AppState Integer
sumST = state $ \(ST lst) -> (sum lst, ST lst)
および (型宣言のみが変更されることに注意してください。実際、型宣言を完全に省略できます!)
append :: MonadState ST m => Integer -> m ()
append v = state $ \(ST lst) -> ((), ST (lst ++ [v]))
sumST :: MonadState ST m => m Integer
sumST = state $ \(ST lst) -> (sum lst, ST lst)
AppState/StateT モナドが基本的な State モナドと同じではないことに気がつき、State モナドに対して sumST と append の両方をコーディングしていました。ある意味では、これらは StateT モナドに持ち上げる必要もありましたが、 in の正しい考え方は、モナドで実行する必要があるということです(したがって、runState script new
)。
完全に理解しているかどうかはわかりませんが、しばらく作業して、MonadState コードを読み、最終的に頭の中で動作するようになったら、これについて何かを書きます。