非空列表作为两个不同的comonads 出现在两个标准结构中。
首先,cofree 共单子是这样给出的。
data Cofree f x = x :& f (Cofree f x) -- every node is labelled with an x
instance Functor f => Functor (Cofree f) where
fmap f (x :& fcx) = f x :& fmap (fmap f) fcx
instance Functor f => Comonad (Cofree f) where
extract (x :& _) = x -- get the label of the top node
duplicate cx@(_ :& fcx) = cx :& fmap duplicate fcx
非空列表可以表示为
type Nellist1 = Cofree Maybe
并且因此是自动共联的。这给了你“尾巴”comonad。
同时,将结构分解为“元素拉链”会产生共元结构。正如我详细解释的那样,
可微性相当于拉链上的这一系列操作(从上下文中挑选出的单个元素并“聚焦”)
class (Functor f, Functor (DF f)) => Diff1 f where
type DF f :: * -> *
upF :: ZF f x -> f x -- defocus
downF :: f x -> f (ZF f x) -- find all ways to focus
aroundF :: ZF f x -> ZF f (ZF f x) -- find all ways to *re*focus
data ZF f x = (:<-:) {cxF :: DF f x, elF :: x}
所以我们得到一个函子和一个comonad
instance Diff1 f => Functor (ZF f) where
fmap f (df :<-: x) = fmap f df :<-: f x
instance Diff1 f => Comonad (ZF f) where
extract = elF
duplicate = aroundF
原则上,这种结构也会产生非空列表。问题是被微分的函子在 Haskell 中并不那么容易表达,尽管导数是合理的。让我们发疯吧...
非空列表相当于ZF thingy x
where DF thingy = []
。我们可以整合列表吗?在代数上愚弄可能会给我们一个线索
[x] = Either () (x, [x]) = 1 + x * [x]
所以作为幂级数,我们得到
[x] = Sum(n :: Nat). x^n
我们可以整合电源系列
Integral [x] dx = Sum(n :: Nat). x^(n+1)/(n+1)
这意味着我们得到了某种大小为 (n+1) 的任意元组,但我们必须将它们识别到等价类的大小为 (n+1) 的某种关系。一种方法是识别到旋转的元组,因此您不知道 (n+1) 个位置中的哪个是“第一个”。
也就是说,列表是非空循环的导数。想想一群人在圆桌旁打牌(可能是纸牌)。旋转桌子,你会得到同样的一群人打牌。但是一旦你指定了庄家,你就可以按照顺时针从庄家左边开始按顺序确定其他玩家的名单。
两种标准结构;同一个函子的两个共子。
(在我之前的评论中,我谈到了多个 monad 的可能性。这有点涉及,但这是一个起点。每个 monadm
也是 applicative,applicative 定律构成m ()
一个 monoid。相应地,每个 monoid 结构m ()
至少给出一个monad 结构的候选对象m
。在 writer monads 的情况下(,) s
,我们得到 monads 的候选对象是与 on 上的 monoids(s,())
相同的 monoids s
。)
编辑非空列表也至少以两种不同的方式是一元的。
我定义了仿函数的身份和配对,如下所示。
newtype I x = I x
data (f :*: g) x = (:&:) {lll :: f x, rrr :: g x}
现在,我可以如下引入非空列表,然后定义连接。
newtype Ne x = Ne ((I :*: []) x)
cat :: Ne x -> Ne x -> Ne x
cat (Ne (I x :&: xs)) (Ne (I y :&: ys)) = Ne (I x :&: (xs ++ y : ys))
这些是一元的,就像可能的空列表一样:
instance Monad Ne where
return x = Ne (I x :&: [])
Ne (I x :&: xs) >>= k = foldl cat (k x) (map k xs)
然而,I
是一个单子:
instance Monad I where
return = I
I a >>= k = k a
此外,单子在配对下是封闭的:
instance (Monad f, Monad g) => Monad (f :*: g) where
return x = return x :&: return x
(fa :&: ga) >>= k = (fa >>= (lll . k)) :&: (ga >>= (rrr . k))
所以我们可以写
newtype Ne x = Ne ((I :*: []) x) deriving (Monad, Applicative, Functor)
但是return
for 那个 monad 给了我们双重的视野。
return x = Ne (I x :&: [x])
所以你有:非空列表是comonadic 两种方式,monadic 两种方式,applicative 六种方式,......
(关于这一点还有很多话要说,但我必须在某个地方停下来。)