Base提供了ZipList,它只是[]
的 Package 器,其中<*>
基于zip
而不是Cartesian-product。这不是默认的,因为它与Monad []
示例不一致,但有些人认为它更直观,而且这两种行为在不同的上下文中都很有用。
Edward Kmett提供了Distributive,它是Traversable
的双通道。一个遍历可以Map/推送/分布到任何应用函数中;分配函数可以从任何函子中提取/分解出来。(由于我还没有打开 Package 的原因,distribute
不要求外层是适用的。
长度索引列表是分布式的,并且按照您所期望的方式工作。具体来说,他们的Applicationinstance是基于zip
*,就像ZipList
* 一样!这表明ZipList
也可能是Distributive
,这将是有用的。Distributive
的文档指出了两件事,任何示例都必须成立:
- “对于某些
x
,它[必须]同构于(->) x
。"*
- “对于某些
- 列表同构于 partial 函数
Int ->
。 - “[它]需要有一种方法来一致地压缩可能无限数量的自身副本。
- 这或多或少就是
ZipList
的存在理由。
这样够了吗今天下午我花了几个小时试着写instance Distributive ZipList where distributive = ...
,但没能让它工作。对于 * 大多数 * 函子f ZipList a
,distribute f
有一个明显的含义,尽管我担心这可能只是因为我没有考虑足够的 * 非 *-可遍历函子。
Maybe
是棘手的;distribute Nothing
应该是[]
还是repeat Nothing
?但是distribute
是sequenceA
的双通道,Traversable Maybe
示例说它应该是repeat Nothing
。(->) e
可能是dealbreaker。- 直观
distribute $ const (repeat x) = repeat (const x)
。 - 我们可以将其扩展到任何保证返回无限列表的函数;它看起来有点像
(\i -> (! i) <$> f) <$> [0..]
。 - 我们可以将 that 扩展到返回有限列表的函数;我们最终得到了一个无限的 * 部分 * 函数列表。我并不认为这是不可接受的部分函数在处理列表时总是出现。
- 但这意味着
distribute $ const [] ≅ repeat undefined
,这有点傻。 - 示例
Applicative ZipList
包含一个重要的设计决策:length (a <*> b) == min (length a) (length b)
(与错误或其他)。我们根本没有利用这一点我可以看到的方式是distribute = const []
。
有人看到前进的道路吗?
如果偏函数解释是“可接受的”,我们能用任何比distribute f = (\i -> (!! i) <$> f) <$> [0..]
更不愚蠢的方式来推广吗?
1条答案
按热度按时间ymdaylpp1#
不,它不可能是分布式的。
Pair
的Distributive
示例看起来像这样:现在让我们考虑一下列表示例。(我们暂时忽略
ZipList
噪声,假设基本列表有zippy示例。)我们需要distribute . distribute = id
。假设因此,法律要求:
我们可以将
distribute
的定义替换为Pair
,得到:这是一个问题,因为list的
(<$>)
保留了长度,这里我们要求它在提供相同参数时返回两个不同长度的答案。哎呀!作为替代方案,你可能会对
data Stream a = Cons a (Stream a)
感兴趣,这是一种保证无限的列表类型,它 * 可以 * 成为Distributive
: