简体   繁体   English

Palindrome 和 Danvy 对直接风格的评论

[英]Palindrome and Danvy's remark on direct style

Here is some code deciding whether a list is a palindrome in n+1 comparisons, in "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)      

which can be tested on a few example可以在几个例子上进行测试

-- >>> pal_d1 [1,2,1]
-- True

-- >>> pal_d1 [1,2,2,1]
-- True

-- >>> pal_d1 [1,2,3,4,2,1]
-- False

Danvy claims in " There and back again " there is no direct style solution without a control operator (right before 4.2) due to the non linear use of the continuation in CPS style solution below: 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)          

How is the first code not contradicting this assertion?第一个代码如何不与此断言相矛盾?

(and how is the continuation not used linearly?) (以及如何不线性使用延续?)

He does not claim that there is no solution without a control operator.他没有声称没有控制操作员就没有解决方案。

The continuation is not used linearly and therefore mapping this program back to direct style requires a control operator.延续不是线性使用的,因此将此程序映射回直接样式需要控制运算符。

The context of the paper is to study systematic transformations between direct style and CPS, and the claim of that paragraph is that going back from CPS is tricky if the continuation is used in fancy ways.这篇论文的背景是研究直接风格和 CPS 之间的系统转换,而那段的主张是,如果以花哨的方式使用延续,从 CPS 回归是很棘手的。

With some effort you can wrangle it back into a nice shape, but the question remains, how might a compiler do that automatically?通过一些努力,您可以将其重新调整为一个不错的形状,但问题仍然存在,编译器如何自动执行此操作?

(and how is the continuation not used linearly?) (以及如何不线性使用延续?)

In the paper, the continuation is on the right of andalso ( && ) so it's discarded if the left operand is False .在本文中,延续位于andalso ( && ) 的右侧,因此如果左侧操作数为False则将其丢弃。

In operational semantics, you can view the continuation as an evaluation context, and in that view discarding the continuation corresponds to throwing an exception.在操作语义中,您可以将延续视为评估上下文,并且在该视图中丢弃延续对应于引发异常。 One can certainly do it, but the point is that this requires extra machinery in the source language.当然可以,但关键是这需要源语言中的额外机制。

The CPS code (in the question's original version --- since edited by OP) seems faulty. CPS 代码(在问题的原始版本中——因为由 OP 编辑)似乎有问题。 Looks like it should be看起来应该是

      walk (x:xs) (_:_:ys) k  =  walk xs ys (\(z:zs) -> x == z && k zs)

The non-CPS code starts the comparisons from the middle, and does n `div` 2 comparisons, for a list of length n .非 CPS 代码从中间开始比较,对长度为n的列表进行n `div` 2比较。 It continues testing even if a mismatch is discovered, so, is "linear" .即使发现不匹配,它也会继续测试,因此是"linear"

The CPS code exits right away in such a case because (False && undefined) == False holds;在这种情况下,CPS 代码会立即退出,因为(False && undefined) == False成立; so is "non-linear" . “非线性”也是如此。 The two are not equivalent so the first doesn't say anything about the second.两者相等,因此第一个没有说明第二个。

As the other answer is saying, not calling the continuation amounts to throwing an exception in a code without continuations, what the paper's author apparently calls "the direct [ie, non-CPS(?) --wn] style".正如另一个答案所说,不调用延续相当于在没有延续的代码中抛出异常,该论文的作者显然称之为“直接[即非CPS(?)--wn]风格”。

(I haven't read the paper). (我没有读过论文)。

It isn't difficult at all to code the early-exiting solution in the "direct" style, by the way.顺便说一句,以“直接”风格对早期退出的解决方案进行编码并不难。 We would just use the same turtle-and-hare trick to discover the halves while also building the first half in reverse, and then call and $ zipWith (==) first_half_reversed second_half in Haskell, or its equivalent short-circuiting direct recursive variant, in a strict language like eg Scheme.我们将使用相同的海龟和兔子技巧来发现一半,同时反向构建前半部分,然后在 Haskell 或其等效的短路直接递归变体中调用and $ zipWith (==) first_half_reversed second_half second_half,使用严格的语言,例如 Scheme。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM