Comonad

Monad の圏論的双対。Monad が「値を文脈に入れて作用を積む」なら、Comonad は「文脈付き値から値を取り出し、文脈全体を使って計算する」。extract と extend(または duplicate)が中核。

定義(Monad との対)

Monad mComonad w
入口/出口return :: a -> m aextract :: w a -> a
連結bind :: m a -> (a -> m b) -> m bextend :: w a -> (w a -> b) -> w b
入れ子join :: m (m a) -> m aduplicate :: w a -> w (w a)
直感出力に作用(producer of effects)入力に文脈(context-dependent computation)

extend f は「フォーカスを動かしながら、各位置で周囲の文脈ごと f を適用する」操作。

クラス定義(Haskell 風)

class Functor w => Comonad w where
  extract   :: w a -> a               -- counit。文脈から「今の値」を取り出す
  duplicate :: w a -> w (w a)         -- comultiplication。各位置に「そこを焦点にした文脈」を詰める
  extend    :: (w a -> b) -> w a -> w b

  -- duplicate と extend は相互定義可能(どちらか一方で済む)
  extend f = fmap f . duplicate
  duplicate = extend id

Comonad 則(Monad 則の双対)

extract      . duplicate         = id            -- 左単位(return-bind の双対)
fmap extract . duplicate         = id            -- 右単位
duplicate    . duplicate         = fmap duplicate . duplicate   -- 結合律
-- extend 形: extract . extend f = f,  extend extract = id,  extend f . extend g = extend (f . extend g)

代表例

Store comonad

「現在位置 s」と「位置から値を引く関数 s -> a」の対。スプレッドシートのセルや画像のピクセルのように、周囲を参照して計算するものを表す。

data Store s a = Store (s -> a) s    -- (引く関数, 焦点)

instance Comonad (Store s) where
  extract     (Store f s)   = f s                      -- 焦点の値
  duplicate   (Store f s)   = Store (Store f) s        -- 各位置 s' に「s' を焦点とした Store」を詰める
  extend g    (Store f s)   = Store (\s' -> g (Store f s')) s

-- 1次元の「移動平均」フィルタ: 焦点の左右を見る
peek :: s -> Store s a -> a
peek s' (Store f _) = f s'

blur :: Store Int Double -> Double
blur w = (peek (pos-1) w + extract w + peek (pos+1) w) / 3
  where Store _ pos = w
-- avg = extend blur w で、全位置に一括適用(各位置の文脈ごと blur)

Zipper(リストの焦点付き表現)

data Zipper a = Zipper [a] a [a]   -- (左を逆順, 焦点, 右)

instance Comonad Zipper where
  extract   (Zipper _ x _) = x
  duplicate z = Zipper (iterateMaybe left z) z (iterateMaybe right z)
    -- 各位置に「そこを焦点にした Zipper 全体」が入る
  -- extend f = fmap f . duplicate ⇒ 各位置で近傍を見た f を一括適用

-- Conway のライフゲーム / 1次元 CA は extend rule そのもの:
--   next = extend rule grid   (rule :: Zipper Cell -> Cell が近傍を読む)

なぜ重要か

「周囲の文脈に依存する計算」を一様に扱える。セルオートマトン、画像処理(畳み込み)、スプレッドシート、ストリーム処理、リアクティブ UI が同じ extend の形に乗る。Monad が副作用(effect)のモデルなら、Comonad は文脈・資源要求(coeffect)のモデルになる。

押さえどころ(カード化候補)

関連

Graph