【问题标题】:Can ZipList be Distributive?ZipList 可以是分布式的吗?
【发布时间】:2021-07-20 00:54:03
【问题描述】:

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

Edward Kmett 提供DistributiveTraversable 的双重性。 Traversable 可以映射/推送/分发到任何 Applicative Functor;可以从任何 Functor 中提取/分解分布。 (由于我没有解包的原因,distribute 不需要外层是Applicative。)

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

Distributive 的文档注意两点对于任何实例都必须正确:

  • “对于某些x,它[必须] 与(->) x 同构。”
    • 列表同构于部分函数Int ->
  • “[它]需要有一种方法来持续压缩可能无限数量的自身副本。”
    • 这或多或少是ZipList存在理由

这样就够了吗?今天下午我花了几个小时试图写instance Distributive ZipList where distributive = ... 并不能完全让它工作。对于大多数函子f ZipList adistribute f 有一个明显的含义,尽管我担心这可能只是因为我没有考虑足够的-可遍历函子。

  • Maybe 很棘手; distribute Nothing 应该是 [] 还是 repeat Nothing?但是distributesequenceA 的对偶,Traversable Maybe 实例说它应该是repeat Nothing
  • (->) e 可能会破坏交易。
    • 直观distribute $ const (repeat x) = repeat (const x)
    • 我们可以将其扩展到任何保证返回无限列表的函数;有点像(\i -> (! i) <$> f) <$> [0..]
    • 我们可以将 that 扩展到返回有限列表的函数;我们最终得到了一个无限的 partial 函数列表。这对我来说并不明显,这是不可接受的。使用列表时,部分函数会一直显示。
    • 但这意味着distribute $ const [] ≅ repeat undefined,这有点傻。
    • 实例Applicative ZipList 包含一个重要的设计决策:length (a <*> b) == min (length a) (length b)(而不是错误或其他)。我们根本没有利用它。我可以看到我们可能会是distribute = const []

有人看到前进的方向吗?

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

【问题讨论】:

    标签: haskell applicative traversable


    【解决方案1】:

    不,不能分配。

    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"
    

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

    作为替代方案,您可能对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))
    

    【讨论】:

    • distribute . distribute = id 肯定会关闭它,我看到它在文档中简要提到过;谢谢!
    • Typeclass 应该在他们的文档中真正列出反例(如Phil Freeman's Counterexamples of Type Classes),因为它们对塑造直觉最有帮助,Distributive ZipList 将是一个很好的补充,尽管 Edward Kmett 正在强调发布一个完全改变的新版本Distributive
    猜你喜欢
    • 2021-10-16
    • 2018-03-18
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    相关资源
    最近更新 更多