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 を使うしかないと思います。

同様の計算は mapMState モナドにより表現可能です:

#!/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)

mapAccumLTraversable なデータ型にしか適用できませんが、mapM なら Vector に対しても適用できます。

例: do 記法

TODO: ポイントフリースタイルの恩恵

TODO: パフォーマンスへの (悪) 影響