证明流的相等性

发布于 2024-10-20 15:31:37 字数 794 浏览 2 评论 0原文

我有玫瑰树的数据类型

data N a = N a [N a]

和应用实例

instance Applicative N where
 pure a = N a (repeat (pure a))
 (N f xs) <*> (N a ys) = N (f a) (zipWith (<*>) xs ys)

,需要证明它的应用定律。然而,pure创造了无限深、无限分支的树。因此,例如,在证明同态定律时,

pure f <*> pure a = pure (f a)

我认为

zipWith (<*>) (repeat (pure f)) (repeat (pure a)) = repeat (pure (f a))

通过近似(或取)引理来证明等式是可行的。然而,我的尝试导致归纳步骤中的“恶性循环”。特别是,减少

approx (n + 1) (zipWith (<*>) (repeat (pure f)) (repeat (pure a))

给出

(pure f <*> pure a) : approx n (repeat (pure (f a)))

其中 approx 是近似函数。 如何在没有明确的共归纳证明的情况下证明等式?

I have a data type

data N a = N a [N a]

of rose trees and Applicative instance

instance Applicative N where
 pure a = N a (repeat (pure a))
 (N f xs) <*> (N a ys) = N (f a) (zipWith (<*>) xs ys)

and need to prove the Applicative laws for it. However, pure creates infinitely deep, infinitely branching trees. So, for instance, in proving the homomorphism law

pure f <*> pure a = pure (f a)

I thought that proving the equality

zipWith (<*>) (repeat (pure f)) (repeat (pure a)) = repeat (pure (f a))

by the approximation (or take) lemma would work. However, my attempts lead to "vicious circles" in the inductive step. In particular, reducing

approx (n + 1) (zipWith (<*>) (repeat (pure f)) (repeat (pure a))

gives

(pure f <*> pure a) : approx n (repeat (pure (f a)))

where approx is the approximation function. How can I prove the equality without an explicit coinductive proof?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

恏ㄋ傷疤忘ㄋ疼 2024-10-27 15:31:37

我会使用展开的通用属性(因为重复和适当的非柯里化的 zipWith 都是展开的)。 我的博客上有相关讨论。但您可能也喜欢 Ralf Hinze 关于独特固定点的论文 ICFP2008< /a>(以及随后的 JFP 论文)。

(只是检查一下:你所有的玫瑰树都是无限宽和无限深?我猜否则法律不会成立。)

I'd use the universal property of unfolds (since repeat and a suitably uncurried zipWith are both unfolds). There's a related discussion on my blog. But you might also like Ralf Hinze's papers on unique fixpoints ICFP2008 (and the subsequent JFP paper).

(Just checking: all your rose trees are infinitely wide and infinitely deep? I'm guessing that the laws won't hold otherwise.)

手长情犹 2024-10-27 15:31:37

以下是我认为有效并保持在程序语法和等式推理层面的一些内容的草图。

基本直觉是,一般来说,推理 repeat x 比推理流(更糟糕的是列表)要容易得多。

uncons (repeat x) = (x, repeat x)

zipWithAp xss yss = 
    let (x,xs) = uncons xss
        (y,ys) = uncons yss
    in (x <*> y) : zipWithAp xs ys

-- provide arguments to zipWithAp
zipWithAp (repeat x) (repeat y) = 
    let (x',xs) = uncons (repeat x)
        (y',ys) = uncons (repeat y)
    in (x' <*> y') : zipWithAp xs ys

-- substitute definition of uncons...
zipWithAp (repeat x) (repeat y) = 
    let (x,repeat x) = uncons (repeat x)
        (y,repeat y) = uncons (repeat y)
    in (x <*> y) : zipWithAp (repeat x) (repeat y)

-- remove now extraneous let clause
zipWithAp (repeat x) (repeat y) = (x <*> y) : zipWithAp (repeat x) (repeat y)

-- unfold identity by one step
zipWithAp (repeat x) (repeat y) = (x <*> y) : (x <*> y) : zipWithAp (repeat x) (repeat y)

-- (co-)inductive step
zipWithAp (repeat x) (repeat y) = repeat (x <*> y)

The following is a sketch of something that I think works and remains at the level of programmatic syntax and equational reasoning.

The basic intuition is that it is much easier to reason about repeat x than it is to reason about a stream (and worse yet, a list) in general.

uncons (repeat x) = (x, repeat x)

zipWithAp xss yss = 
    let (x,xs) = uncons xss
        (y,ys) = uncons yss
    in (x <*> y) : zipWithAp xs ys

-- provide arguments to zipWithAp
zipWithAp (repeat x) (repeat y) = 
    let (x',xs) = uncons (repeat x)
        (y',ys) = uncons (repeat y)
    in (x' <*> y') : zipWithAp xs ys

-- substitute definition of uncons...
zipWithAp (repeat x) (repeat y) = 
    let (x,repeat x) = uncons (repeat x)
        (y,repeat y) = uncons (repeat y)
    in (x <*> y) : zipWithAp (repeat x) (repeat y)

-- remove now extraneous let clause
zipWithAp (repeat x) (repeat y) = (x <*> y) : zipWithAp (repeat x) (repeat y)

-- unfold identity by one step
zipWithAp (repeat x) (repeat y) = (x <*> y) : (x <*> y) : zipWithAp (repeat x) (repeat y)

-- (co-)inductive step
zipWithAp (repeat x) (repeat y) = repeat (x <*> y)
_失温 2024-10-27 15:31:37

为什么需要共感应?只是感应。

pure f <*> pure a = pure (f a)

也可以写成(你需要证明左右相等),

N f [(pure f)] <*> N a [(pure a)] = N (f a) [(pure (f a))]

它允许你一次删除一项。这给了你你的感应。

Why do yo need coinduction? Just induct.

pure f <*> pure a = pure (f a)

can also be written (you need to prove the left and right equality)

N f [(pure f)] <*> N a [(pure a)] = N (f a) [(pure (f a))]

which allows you to off one term at a time. That gives you your induction.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文