3

State'いくつかのデータを使って私のプログラムの状態にしましょう。

type State' m a = StateT Int m a

いくつかの計算で使用します。

例:

-- genData, return some string (using Int value and State')
genData :: Int -> State' String
genData n = ...

-- genDatas, return multiple strings
genDatas :: Int -> State' [String]
genDatas n = mapM genData [1..n]

-- printLog, write log message (enumerating lines)
printLog :: String -> State' IO ()
printLog msg = do
  n <- get
  let n' = n + 1
  put n'
  liftIO $ putStrLn $ "Message #" ++ (show n') ++ ": " ++ msg

私はそれを行う正しい方法ではないと思います:

-- If I need a "in context function" returning a Int value...
--
-- addExtra, return current Int in state plus x
addExtra :: Int -> State' Identity Int
addExtra x = get >>= return.(+x)

addExtraいくつかのモナドコンテキストで関数を使用するには、次のようにします。

doComplex :: State' IO ()
doComplex = do
  printLog "Starting process..."

  -- It's ugly!
  s <- get
  Identity (w, s') <- return $ runStateT (addExtra 5) s
  put s' -- save state

  printLog $ "computed value: " ++ (show w)

State'さまざまな機能に沿ってモナドを共有する正しい方法は何ですか?(IO aそうしているように)

ありがとうございました!

(私はいくつかのチュートリアルといくつかのソースコードを読みましたが、それを理解できません)

4

1 に答える 1

5

あなたの質問に答える

addExtra関数は基礎となるモナドに対して実際には何もしないので、型シグネチャを変更してモナドに依存しないようにすることができます:

addExtra :: Monad m => Int -> State' m Int
addExtra x = get >>= return . (+x)

今、あなたはこれを書くことができます

doComplex :: State' IO ()
doComplex = do
    printLog "Starting process..."

    w <- addExtra 5

    printLog $ "Computed value: " ++ show w

これははるかにきれいで、古いコードと同じように機能します。

*Main> runStateT doComplex 0
Message #1: Starting process...
Message #2: Computed value: 6
((),2)

さておき

おそらく、次のいずれかに書き直したくなるでしょうaddExtra。まず、 do 表記を使用します

addExtra x = do s <- get
                return (s + x)

またはliftM、モナドがあるという事実を実際には使用していないため、を使用する

addExtra x = liftM (+x) get

または使用することもできますgets(コメントのDaniel Wagnerに感謝します)

addExtra x = gets (+x)

もちろん、この時点では、おそらく追加機能は必要ありません。あなたはちょうど書くかもしれません

doComplex = do printLog "Starting process..."
               w <- gets (+5)
               printLog $ "Computed value: " ++ show w

同様に、おそらく書き直しprintLogます。get状態を操作し、それに何かを行って、putそれを元に戻す場合は、おそらく単に を使用したいと思うでしょうmodify

printLog msg = do modify (+1)
                  n <- get
                  liftIO . putStrLn $ "Message #" ++ show n ++ ": " ++ msg
于 2012-10-31T11:38:05.883 に答える