ZipList可以是分布式的吗?
Base 提供ZipList,它只是[]where <*>is basedzip而不是笛卡尔积的包装器。这不是默认设置,因为它与Monad []实例不一致,但有些人发现它更直观,并且这两种行为在不同的上下文中都很有用。
Edward Kmett 提供Distributive,Traversable. 一个 Traversable 可以被映射/推送/分发到任何 Applicative Functor 中;可以从任何 Functor 中提取/分解一个 Distributive。(由于我没有拆包的原因,distribute不需要外层是适用的。)
长度索引列表是 Distributive,并且按您期望的方式工作。具体来说,他们的 Applicative 实例基于zip,就像ZipList! 这表明ZipList也可能是Distributive,这将是有用的。
文档的Distributive注意事项必须是任何实例的两件事:
- “
(->) x对于某些人来说,它 [必须] 同构x。”- 列表与偏函数同构
Int ->。
- 列表与偏函数同构
- “[它] 需要有一种方法来始终如一地压缩可能无限数量的自身副本。”
- 这是更多或更少的存在的理由的
ZipList。
- 这是更多或更少的存在的理由的
这够好吗?今天下午我花了几个小时试图写作instance Distributive ZipList where distributive = ...,但无法让它发挥作用。对于大多数函子,f ZipList a有一个明显的含义distribute f,尽管我担心这可能只是因为我没有考虑足够的非可遍历函子。
Maybe很棘手;应该distribute Nothing是[]还是repeat Nothing?但是distribute是对的sequenceA,Traversable Maybe实例说它应该是repeat Nothing。(->) e可能是交易破坏者。- 直觉上
distribute $ const (repeat x) = repeat (const x)。 - 我们可以将其扩展到任何保证返回无限列表的函数;它看起来有点像
(i -> (! i) <$> f) <$> [0..]。 - 我们可以将其扩展到返回有限列表的函数;我们最终得到了一个无限的偏函数列表。对我来说,这是不可接受的并不明显。在处理列表时,部分函数总是会出现。
- 但这意味着
distribute $ const [] ? repeat undefined,这有点愚蠢。 - 该实例
Applicative ZipList包含一个重要的设计决策:(length (a <*> b) == min (length a) (length b)与错误或其他什么相反)。我们根本没有利用它。我可以看到我们可能会的方式distribute = const []。
- 直觉上
有没有人看到前进的道路?
如果部分函数的解释是“可以接受的”,我们能否以比 更愚蠢的方式概括它distribute f = (i -> (!! i) <$> f) <$> [0..]?
回答
不,它不能是分布式的。
明显的Distributive例子Pair是这样的:
instance Distributive Pair where
distribute vs = Pair (pFst <$> vs) (pSnd <$> vs)
现在让我们考虑一下列表实例。(让我们ZipList暂时忽略噪音,假设基本列表具有 zippy 实例。)我们需要distribute . distribute = id. 认为
x = distribute (Pair "" "a")
因此法律要求:
distribute x = Pair "" "a"
我们可以替换distributefor的定义Pair,得到:
Pair (pFst <$> x) (pSnd <$> x) = Pair "" "a"
这是一个问题,因为列表(<$>)保留长度,这里我们要求它在提供相同参数时返回两种不同长度的答案。哎呀!
作为替代方案,您可能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))