我有数据类型
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 是近似函数。 如何在没有明确的共同证明证明的情况下证明平等?
答案 0 :(得分:4)
我会使用展开的通用属性(因为重复和适当的不合格的拉链都展开)。有一个相关的讨论on my blog。但您可能也喜欢Ralf Hinze关于独特修复点ICFP2008(以及随后的JFP论文)的论文。
(只是检查一下:你所有的玫瑰树都是无限宽而且无限深?我猜这些法则不会另有规定。)
答案 1 :(得分:3)
以下是我认为有效并且仍然处于程序化语法和等式推理水平的草图。
基本的直觉是,推理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)
答案 2 :(得分:1)
为什么你需要共同诱导?只是归纳。
pure f <*> pure a = pure (f a)
也可以写(你需要证明左右相等)
N f [(pure f)] <*> N a [(pure a)] = N (f a) [(pure (f a))]
允许您一次关闭一个词。这会给你感应。