[英]What are the adjoint functor pairs corresponding to common monads in Haskell?
在類別理論中,monad可以用兩個伴隨的仿函數構造。 特別是,如果C和D是類別而F:C - > D和G:D - > C是伴隨函子,在某種意義上說是雙射
hom(FX,Y)= hom(X,GY)
對於C中的每個X和D中的 Y ,則組合物G o F:C→C是單子。
可以通過固定類型b
並取F
和G
來給出一對這樣的伴隨函子
data F b a = F (a,b)
data G b a = G (b -> a)
instance Functor (F b) where
fmap f (F (a,b)) = F (f a, b)
instance Functor (G b) where
fmap f (G g) = G (f . g)
並且通過currying給出了hom-sets之間的雙射(模數構造函數):
iso1 :: (F b a -> c) -> a -> G b c
iso1 f = \a -> G $ \b -> f (F (a,b))
iso2 :: (a -> G b c) -> F b a -> c
iso2 g = \(F (a,b)) -> let (G g') = g a in g' b
在這種情況下相應的monad是
data M b a = M { unM :: b -> (a,b) }
instance Monad (M b) where
return a = M (\b -> (a,b))
(M f) >>= g = M (\r -> let (a,r') = f r in unM (g r') a)
我不知道這個monad的名字應該是什么,除了它看起來像是一個讀者monad,它帶有一些可寫的信息( 編輯: dbaupp在評論中指出這是State
monad 。)
所以State
monad可以被“分解”為一對伴隨函子F
和G
,我們可以寫
State = G . F
到現在為止還挺好。
我現在正在試圖弄清楚如何將其他常見的monad分解為成對的伴隨函子 - 例如Maybe
, []
, Reader
, Writer
, Cont
- 但我無法弄清楚我們可以“成對的伴隨函子對”將它們分解為。
唯一的簡單情況似乎是Identity
單子,它可以被分解成任何對函子F
和G
使得F
是逆G
(在尤其,可以只取F = Identity
和G = Identity
)。
任何人都能解釋一下嗎?
您正在尋找的是Kleisli類別 。 最初開發它是為了表明每個monad都可以用兩個伴隨的仿函數構造。
問題是Haskell Functor
不是通用函子,它是Haskell類中的endo-functor。 所以我們需要不同的東西(AFAIK)來表示其他類別之間的仿函數:
{-# LANGUAGE FunctionalDependencies, KindSignatures #-}
import Control.Arrow
import Control.Category hiding ((.))
import qualified Control.Category as C
import Control.Monad
class (Category c, Category d) => CFunctor f c d | f -> c d where
cfmap :: c a b -> d (f a) (f b)
請注意,如果我們對c
和d
都采用->
,我們得到一個Haskell類的endo-functor,它只是fmap
的類型:
cfmap :: (a -> b) -> (f a -> f b)
現在我們有明確的類型類,它表示兩個給定類別c
和d
之間的仿函數,我們可以表示給定monad的兩個伴隨仿函數。 左邊的一個將對象a
映射到a
並將態射f
映射到(return .) f
:
-- m is phantom, hence the explicit kind is required
newtype LeftAdj (m :: * -> *) a = LeftAdj { unLeftAdj :: a }
instance Monad m => CFunctor (LeftAdj m) (->) (Kleisli m) where
cfmap f = Kleisli $ liftM LeftAdj . return . f . unLeftAdj
-- we could also express it as liftM LeftAdj . (return .) f . unLeftAdj
右邊的一個將對象a
映射到對象ma
並將一個態射g
映射到join . liftM g
join . liftM g
,或等效於(=<<) g
:
newtype RightAdj m a = RightAdj { unRightAdj :: m a }
instance Monad m => CFunctor (RightAdj m) (Kleisli m) (->) where
cfmap (Kleisli g) = RightAdj . join . liftM g . unRightAdj
-- this can be shortened as RightAdj . (=<<) g . unRightAdj
(如果有人知道如何在Haskell中表達這一點,請告訴我。)
Maybe
是從免費的仿函數到尖頭套裝和健忘的仿函數回來 []
來自免費的仿函數,進入幺半群和健忘的仿函數 但這些類別都不是Hask的子類別。
正如你所觀察到的,每一對伴隨的仿函數都會產生一個monad。 反之亦然:每個monad都以這種方式出現。 事實上,它以兩種規范的方式實現。 一個是Kleisli建築Petr描述的; 另一個是Eilenberg-Moore建築。 實際上,Kleisli是最初的這種方式,而EM是最終的方式,在一對合適的伴隨仿函數中。 他們是在1965年獨立發現的。如果你想要細節,我強烈推薦Catsters視頻 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.