State
例: State
モナドで mapAccumL
mapAccumL
は状態を持った map
関数です。累積和を計算してみます:
#!/usr/bin/env stack
import Data.List
main :: IO ()
main = do
-- 数列 → 累積和
-- [1, 2, 3] -> (6, [1, 3, 6])
print $ mapAccumL (\acc x -> (acc + x, acc + x)) (0 :: Int) [1, 2, 3]
-- 累積和 → 数列
-- [1, 3, 6] -> (6, [1, 2, 3])
print $ mapAccumL (\lastX x -> (x, x - lastX)) (0 :: Int) [1, 3, 6]
累積和の計算には fold を使うことができます。しかし累積和を数列に戻す際には
mapAccumL
を使うしかないと思います。
同様の計算は mapM
と State
モナドにより表現可能です:
#!/usr/bin/env stack
import Control.Monad.State
import Data.List
main :: IO ()
main = do
-- 数列 → 累積和
-- [1, 2, 3] -> ([1, 3, 6], 6)
print $ runState (mapM (\x -> state $ \acc -> (x + acc, x + acc)) [1, 2, 3]) (0 :: Int)
-- 累積和 → 数列
-- [1, 3, 6] -> ([1, 2, 3], 0)
print $ runState (mapM (\x -> state $ \lastX -> (x - lastX, x)) [1, 2, 3]) (0 :: Int)
mapAccumL
は Traversable
なデータ型にしか適用できませんが、mapM
なら Vector
に対しても適用できます。
例: do
記法
TODO: ポイントフリースタイルの恩恵
TODO: パフォーマンスへの (悪) 影響