ZipList 可以是分布式的吗?

Can ZipList be Distributive?

Base 提供 ZipList,它只是 [] 的包装器,其中 <*> 基于 zip 而不是笛卡尔积。这不是默认设置,因为它与 Monad [] 实例不一致,但有些人发现它更直观,并且这两种行为在不同的上下文中都很有用。

Edward Kmett 提供 DistributiveTraversable 的对偶。 Traversable 可以 mapped/pushed/distributed 进入任何 Applicative Functor; Distributive 可以是任何 Functor 中的 pulled/factored。 (由于我没有解包的原因,distribute不要求外层是Applicative。)

Length-indexed lists are Distributive,按您期望的方式工作。具体来说,他们的Applicative实例是基于zip就像ZipList一样!这表明 ZipList 也可以是 Distributive,这很有用。

Distributive 的文档指出了任何实例都必须满足的两点:

这样够好吗?今天下午我花了几个小时试图写 instance Distributive ZipList where distributive = ... 但无法让它正常工作。对于 most 函子 f ZipList a 有明显的意义 distribute f,虽然我担心这可能只是因为我没有考虑足够 non -可遍历函子。

有人看到前进的方向吗?

如果部分函数解释是“可接受的”,我们能否以比 distribute f = (\i -> (!! i) <$> f) <$> [0..] 更简单的方式概括它?

不,不能分配。

Pair 的明显 Distributive 实例如下所示:

instance Distributive Pair where
    distribute vs = Pair (pFst <$> vs) (pSnd <$> vs)

现在让我们考虑一下列表实例。 (让我们暂时忽略 ZipList 噪音,假设基本列表有 zippy 实例。)我们需要 distribute . distribute = id。假设

x = distribute (Pair "" "a")

因此法律要求:

distribute x = Pair "" "a"

我们可以用distribute的定义代替Pair,得到:

Pair (pFst <$> x) (pSnd <$> x) = Pair "" "a"

这是一个问题,因为列表的 (<$>) 保留了长度,这里我们要求它 return 在提供相同参数时提供两个不同长度的答案。哎呀!

作为替代方案,您可能对 data Stream a = Cons a (Stream a) 类型的保证无限列表感兴趣,可以 Distributive:

sHead :: Stream a -> a
sHead (Cons a _) = a

sTail :: Stream a -> Stream a
sTail (Cons _ as) = as

instance Distributive Stream where
    distribute streams = Cons (sHead <$> streams) (distribute (sTail <$> streams))