[英]Palindrome and Danvy's remark on direct style
这是一些代码,以“直接样式”确定列表是否是 n+1 比较中的回文
pal_d1 :: Eq a => [a] -> Bool
pal_d1 l = let (r,_) = walk l l in r
where walk l [] = (True,l)
walk l (_:[]) = (True,tail l)
walk (x:l) (_:_:xs) = let (r, y:ys) = walk l xs
in (r && x == y, ys)
可以在几个例子上进行测试
-- >>> pal_d1 [1,2,1]
-- True
-- >>> pal_d1 [1,2,2,1]
-- True
-- >>> pal_d1 [1,2,3,4,2,1]
-- False
Danvy 在“ There and back again ”中声称,由于以下 CPS 风格解决方案中延续的非线性使用,没有控制运算符(在 4.2 之前)没有直接风格的解决方案:
pal_cps1 :: Eq a => [a] -> Bool
pal_cps1 l = walk l l (\_ -> trace "called" True)
where
walk l [] k = k l
walk l (_:[]) k = k (tail l)
walk (x:xs) (_:_:ys) k = walk xs ys (\(r:rs) -> x == r && k rs)
第一个代码如何不与此断言相矛盾?
(以及如何不线性使用延续?)
他没有声称没有控制操作员就没有解决方案。
延续不是线性使用的,因此将此程序映射回直接样式需要控制运算符。
这篇论文的背景是研究直接风格和 CPS 之间的系统转换,而那段的主张是,如果以花哨的方式使用延续,从 CPS 回归是很棘手的。
通过一些努力,您可以将其重新调整为一个不错的形状,但问题仍然存在,编译器如何自动执行此操作?
(以及如何不线性使用延续?)
在本文中,延续位于andalso
( &&
) 的右侧,因此如果左侧操作数为False
则将其丢弃。
在操作语义中,您可以将延续视为评估上下文,并且在该视图中丢弃延续对应于引发异常。 当然可以,但关键是这需要源语言中的额外机制。
CPS 代码(在问题的原始版本中——因为由 OP 编辑)似乎有问题。 看起来应该是
walk (x:xs) (_:_:ys) k = walk xs ys (\(z:zs) -> x == z && k zs)
非 CPS 代码从中间开始比较,对长度为n
的列表进行n `div` 2
比较。 即使发现不匹配,它也会继续测试,因此是"linear" 。
在这种情况下,CPS 代码会立即退出,因为(False && undefined) == False
成立; “非线性”也是如此。 两者不相等,因此第一个没有说明第二个。
正如另一个答案所说,不调用延续相当于在没有延续的代码中抛出异常,该论文的作者显然称之为“直接[即非CPS(?)--wn]风格”。
(我没有读过论文)。
顺便说一句,以“直接”风格对早期退出的解决方案进行编码并不难。 我们将使用相同的海龟和兔子技巧来发现一半,同时反向构建前半部分,然后在 Haskell 或其等效的短路直接递归变体中调用and $ zipWith (==) first_half_reversed second_half
second_half,使用严格的语言,例如 Scheme。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.