[英]What is a cocartesian comonoid, and what is a cocartesian comonoidal functor?
我最近一直在試驗幺半群和分布,我想我發現了一些有趣的東西(在我的回答中描述)——這些是已知的結構嗎? (我一直無法在網上找到對它們的任何參考,而且我認為我沒有錯過一些它們會荒謬的原因)
如果以前不知道,它們對我以外的任何人來說是否有用或有趣?
引導我到這里的問題是:
以下內容對這些結構背后的規律相當簡單,因為它們是最近的實驗產物。
首先,cocartesian comagma,加上身份:
-- modified to an equivalent definition for clarity
class Semigroup a where
(<>) :: (a,a) -> a
class Semigroup a => Monoid a where
mempty :: () -> a
class Split a where
split :: a -> Either a a
class Idsplit a where
void :: a -> Void
這些是具有固有分支能力的數據類型 - 要成為一個適當的 comonoid,這種分支不應該改變它的值(由於函數的整潔類型類實例),但這會導致對於此處描述的目的而言,類型類的興趣要少得多。
這是函數的實例,對應於 Op 的要求幺半群的 Divisible 實例:
instance Split r => Alt ((->) r) where
(<!>) :: (r -> a) -> (r -> a) -> (r -> a)
f1 <!> f2 = either f1 f2 . split
instance Idsplit r => Alternative ((->) r) where
(<|>) = (<!>)
empty = absurd . void
不幸的是,除非拆分是合法的,否則這不會是關聯的 - 但我認為它的非關聯形式仍然可以使用?
也可以定義一個 Unfoldable 類型類,類似於對於 monoids 的 Foldable,對於 semigroups 的 Foldable1,以及它們理論上的進一步的家庭成員:
class Unfoldable l where
unfoldMap :: Split m => (m -> e) -> (m -> l e)
instance Unfoldable [] where
unfoldMap strat root = case strat root of
Left m -> []
Right m -> m : unfoldMap strat root
newtype Unfolder a = Unfolder { getUnfolder :: (a, a -> Maybe a) }
instance Split (Unfolder a) where
unfoldr :: (a -> Maybe (e,a)) -> (a -> [e])
unfoldr strat root = unfoldMap
(fst . fst . getUnfolder)
(Unfolder ((undefined, root), (strat . snd)))
-- uses Unfolder (e,a) similar to Endo a in foldr
-- the undefined will be dropped by list's instance of Unfoldable, and so is safe
下一個:我認為是“cocartesian 聯合函子”:
class Functor f => Match f where
matchWith :: (c -> Either a b) -> f c -> Either (f a) (f b)
class Match f => Matchable f where
voidWith :: (a -> Void) -> f a -> Void
-- Maybe is a Match, but not a Matchable due to Nothing
instance Match Maybe where
matchWith _ Nothing = Left Nothing
matchWith choose (Just a) = bimap Just Just $ choose a
-- this won't work
instance Matchable Maybe where
voidWith void (Just a) = void a
voidWith void Nothing = ?????
-- Pick always needs an a value, and so is Matchable as well
data Pick a = Pick1 a | Pick2 a
deriving Functor
instance Match Pick where
matchWith choose (Pick1 a) = bimap Pick1 Pick1 $ choose a
matchWith choose (Pick2 a) = bimap Pick2 Pick2 $ choose a
instance Matchable Pick where
voidWith void (Pick1 a) = void a
voidWith void (Pick2 a) = void a
對於代數數據類型,Match 描述了在每個構造函數中最多具有一個值的函子(然后可以對其進行觀察和模式匹配)。
Matchable 描述了在每個構造函數中只有一個值的函子(因此無人居住的值會導致無人居住的函子)。
我相信 Matchable 比使用 Functor 而不是 Applicative 遍歷的 Traversable 類型類嚴格弱,但尚未證明這一點 - 這將對應於所有 Distributives 都是 Applicative。 (每個構造函數中只有一個參數值的所有代數數據類型都是可匹配和可遍歷的。)
class Functor l => FTraversable l where
ftraverse :: Functor f => (a -> f b) -> (l a -> f (l b))
instance FTraversable f => Match f where
matchWith choose fc =
let fab = fmap choose fc :: f (Either a b)
afb = fsequence fab :: Either a (f b)
bfa = fsequence (fmap swap fab) :: Either b (f a)
in case (afb, bfa) of
(Left a, Right (f a)) -> Left (f a)
(Right (f b), Left b) -> Right (f b)
(_, _) -> undefined -- impossible?
instance FTraversable f => Matchable f where
voidWith void fa = (absurd1 :: forall a. V1 a -> Void) . ftraverse ((absurd :: Void -> V1 ()) . void) $ fa
instance Matchable l => FTraversable l where
ftraverse strat la = ???
Matchables 對我來說似乎很有趣,它是我無法找到任何參考的擴展應用程序家族的一部分,但它們確實與來自“分布式”庫(Traversables 的對偶)中的分布式函子結合在一起。
對於某些 r,正態分布與Reader r
同構,並且著名(我認為至少是著名的?這似乎眾所周知)等價於可表示函子,或 Hask 中的右伴隨。 解釋為代數數據類型,它們是只有一個構造函數的代數數據類型。
不過,這些可以擴展到基於 Functor 的分布式之外!
-- all defined using cotraverse instead of distribute, for clarity
-- (which is equivalent to using distribute)
-- isomorphic to Reader r (f a) for some r and Matchable f, not sure which
-- for algebraic datatypes, those with a finite constructor count
class Functor l => MatchableDistributive l where
cotraverseMatchable :: Matchable f => (f a -> b) -> (f (l a) -> l b)
-- isomorphic to Reader r (f a) for some r and Match f, not sure which
-- for algebraic datatypes, those with a finite non-zero constructor count
class MatchableDistributive l => MatchDistributive l where
cotraverseMatch :: Match f => (f a -> b) -> (f (l a) -> l b)
-- isomorphic to Reader r a for some r ~ Rep l
-- for algebraic datatypes, those with exactly one constructor
class MatchDistributive l => Distributive l where
cotraverse :: Functor f => (f a -> b) -> (f (l a) -> l b)
這些鏡像 Traversable ~ (l (), [a])
, Traversable1 ~ (l (), NonEmpty a)
和更罕見的函子可遍歷 ~ (l (), a)
。
(有趣的是:對於代數數據類型,每個 Traversable 系列成員的記錄與 Distributive 等價物的構造函數一樣多,反之亦然)
(有趣的是:正如 Coapplicatives 在 Hask 中微不足道一樣,Comatchables 也是如此——我希望這可以解釋為 Coapplicatives 啟用了 Distributive 的許多記錄,而 Comatchables 啟用了 Traversable 的許多構造函數?)
Matchables 也像 Applicatives 一樣定義通用實例,除了它是具有唯一 Applicative 實例的 Applicatives 的產品,它實際上是具有唯一實例的 Matchables 的總和!
Cocartesian Coapplicatives 充當替代等價物 - Cocartesian Coapply 可以解釋為能夠選擇在“解壓縮”操作中采用哪一側,而 Cocartesian Coapplicative 描述了一個完全無人居住的仿函數,如泛型中的 V1。
class Functor f => Bias f where
biasWith :: (c -> (a,b)) -> f c -> Either (f a) (f b)
class Bias f => Biasable f where
devoidWith :: (a -> ()) -> (f a -> Void)
-- empty analogue
devoid :: Biasable f => f a -> Void
devoid = devoidWith (const ())
-- (<|>) analogue
biasing :: Bias f => f a -> Either (f a) (f a)
biasing = biasWith (\a -> (a,a))
總之:
這里有 4 種類型的幺半群(monoid、comonoid、cocartesian monoid、cocartesian comonoid),其中第一個和最后一個在 Hask 中是非平凡的。 如果您包括這些以及 (,) 和 Either,也許有 6 個?
這里有 applicative 家族的 6 個成員(applicative、alternative、dividible、decidable、matchable、biasable),加上瑣碎的 coapplicative 和 comatchable——這大概可以進一步填寫到總共 16 個成員! 或 36 個,包括上述這些
可匹配函子啟用較弱版本的分布式 - 其中分布式的數據始終存在,匹配分布中的數據僅有時存在,或可能永遠不存在於可匹配分布中
(這些明智的 applicative = Align 來自 'semialign' 包,但規則更少?對應於 applicatives 和 zips 之間的關系,在 ZipList 的類型類實例中看到?)
編輯:列表的更對稱的 Unfoldable 實例
使用與 Monofoldable 類型類類似的方法,可以將左偏或右偏的選擇留到事后。
class MonoUnfoldable l e | l -> e where
unfoldMapMono :: Split m => (m -> e) -> (m -> l)
-- this will always create an infinite list
instance MonoUnfoldable [Either a a] (Either a a) where
unfoldMapMono strat m = strat m : unfoldMapMono strat m
pickLefts, pickRights :: [Either a a] -> [a]
pickLefts (Left a : as) = a : pickLefts as
pickLefts _ = []
pickRights (Right a : as) = a : pickRights as
pickRights _ = []
但是,用於展開的有用拆分實例將改變值,並且已經為這些值變化選擇了左/右偏差。 例如:
instance Num n => Split (Sum n) where
split (Sum n)
| n > 0 = Right $ Sum (n-1)
| otherwise = Left $ Sum (n-1)
unfoldMap getSum (Sum 10) = [9,8,7,6,5,4,3,2,1,0]
因此,不對稱性實際上是該過程所固有的,並且所需要的只是對於左或右是否表示列表狀(線性,有限)展開的終點保持一致。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.