两个延续如何相互抵消?

约瑟夫·西布尔-恢复莫妮卡:

我正在阅读列表操作的一些技巧,其中包含以下内容:

zipRev xs ys = foldr f id xs snd (ys,[])
  where
    f x k c = k (\((y:ys),r) -> c (ys,(x,y):r)) 

我们在这里可以看到的是,我们有两个彼此叠放的延续。发生这种情况时,他们通常可以“取消”,如下所示:

zipRev xs ys = snd (foldr f (ys,[]) xs)
  where
    f x (y:ys,r) = (ys,(x,y):r)

我不明白您如何“取消”堆叠的延续以从顶部的代码块到达底部的代码块。您寻找进行此转换的方式是什么,为什么行得通?

user11228628:

函数f :: a -> b可以“伪装”双延续作为一个函数内f' :: ((a -> r1) -> r2) -> ((b -> r1) -> r2)

obfuscate :: (a -> b) -> ((a -> r1) -> r2) -> (b -> r1) -> r2
obfuscate f k2 k1 = k2 (k1 . f)

obfuscate具有很好的属性,可以保留函数的组成和身份:您可以通过几个步骤证明这obfuscate f . obfuscate g === obfuscate (f . g)一点obfuscate id === id这意味着您可以经常使用此变换来解开组成obfuscated函数的双连续计算,方法obfuscate是将合成中的因子分解出来。这个问题就是这样一个例子。

f在顶部的代码块是obfuscate的d版本f在底块(更确切地说,顶部f xobfuscate底部的d版本f x)。您可以通过注意到top如何f将外部延续应用到转换其输入的函数,然后将整个事物应用到内部延续来看到这一点,就像在主体中一样obfuscate

这样我们就可以解开纠结zipRev

zipRev xs ys = foldr f id xs snd (ys,[])
  where
    f x = obfuscate (\(y:ys,r) -> (ys,(x,y):r))

由于foldr此处的作用obfuscate彼此构成一堆d函数(并将其全部应用到id,我们可以在右边保留),因此我们可以将d函数分解为obfuscate整个折叠的外部:

zipRev xs ys = obfuscate (\accum -> foldr f accum xs) id snd (ys,[])
  where
    f x (y:ys,r) = (ys,(x,y):r)

现在应用的定义obfuscate并简化:

zipRev xs ys = obfuscate (\accum -> foldr f accum xs) id snd (ys,[]) 
zipRev xs ys = id (snd . (\accum -> foldr f accum xs)) (ys,[])
zipRev xs ys = snd (foldr f (ys,[]) xs)

QED!

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章