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: パフォーマンスへの (悪) 影響