Profunctorの定義
class Profunctor p where
dimap :: (a -> b) -> (c -> d) -> p b c -> p a d
dimap f g = lmap f . rmap g
lmap :: (a -> b) -> p b c -> p a c
lmap f = dimap f id
rmap :: (b -> c) -> p a b -> p a c
rmap = dimap id
Profunctorは2つの型パラメータを持つ型クラスで、第1引数が反変(contravariant)、第2引数が共変(covariant)な性質を持ちます。主要な関数は以下の通り:
dimap: 双方向の変換を行い、Profunctorの両パラメータを同時に変更lmap: 左側(反変)パラメータのみを変換rmap: 右側(共変)パラメータのみを変換
Profunctorは入出力の概念を一般化し、p b cにおいて入力bは反変、出力cは共変として振る舞います。
Profunctor則
-- 基本法則
dimap id id ≡ id
lmap id ≡ id
rmap id ≡ id
dimap f g ≡ lmap f . rmap g
-- 派生法則
dimap (f . g) (h . i) ≡ dimap g h . dimap f i
lmap (f . g) ≡ lmap g . lmap f
rmap (f . g) ≡ rmap f . rmap g
関数型のProfunctorインスタンス
instance Profunctor (->) where
dimap pre post fn = post . fn . pre
lmap pre fn = fn . pre
rmap = (.)
ghci> lmap (+2) (*3) 4 -- (4+2)*3 = 18
18
ghci> rmap (+3) (*3) 4 -- 4*3+3 = 15
15
ghci> dimap (+2) (+3) (*3) 4 -- (4+2)*3+3 = 21
21
関数型(->)は典型的なProfunctorであり、dimap (+2) (+3) (*3)は(+3) . (*3) . (+2)と等価です。
Star型のProfunctor実装
newtype Star f d c = Star { runStar :: d -> f c }
instance Functor f => Profunctor (Star f) where
dimap pre post (Star fn) = Star (fmap post . fn . pre)
lmap k (Star f) = Star (f . k)
rmap k (Star f) = Star (fmap k . f)
StarはFunctorをProfunctorに変換します。実装例:
ghci> runStar (dimap (+1) show (Star Just)) 5
Just "6" -- fmap show . Just . (+1) $ 5
Costar型のProfunctor実装
newtype Costar f d c = Costar { runCostar :: f d -> c }
instance Functor f => Profunctor (Costar f) where
dimap pre post (Costar fn) = Costar (post . fn . fmap pre)
lmap k (Costar f) = Costar (f . fmap k)
rmap k (Costar f) = Costar (k . f)
ghci> runCostar (dimap (+1) show (Costar sum)) [1,2,3]
"9" -- show . sum . fmap (+1) $ [1,2,3]
Forget型のProfunctor実装
newtype Forget r a b = Forget { runForget :: a -> r }
instance Profunctor (Forget r) where
dimap pre _ (Forget k) = Forget (k . pre)
lmap pre (Forget k) = Forget (k . pre)
rmap _ (Forget k) = Forget k