【问题标题】:Palindrome and Danvy's remark on direct stylePalindrome 和 Danvy 对直接风格的评论
【发布时间】:2021-06-10 15:01:51
【问题描述】:

这里是一些代码,用于确定列表是否为 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”中声称没有控制运算符(在 4.2 之前)没有直接的风格解决方案,因为在下面的 CPS 风格解决方案中非线性使用延续:

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)          

第一个代码如何不与此断言相矛盾?

(以及如何不线性使用延续?)

【问题讨论】:

  • 还请注意,该论文使用的是严格的 ML(语言)。至于你的 Haskell 代码,看看如果我们将第一个版本的最后一行更改为 in (x == y && r, ys) 会发生什么。

标签: haskell recursion continuations continuation-passing callcc


【解决方案1】:

他并没有声称没有控制操作员就没有解决方案。

延续不是线性使用的,因此将此程序映射回直接样式需要控制运算符。

本文的背景是研究直接风格和 CPS 之间的系统转换,并且该段落的主张是,如果以花哨的方式使用延续,则从 CPS 退回是棘手的。

通过一些努力,您可以将其重新调整为漂亮的形状,但问题仍然存在,编译器如何自动做到这一点?

(以及如何不线性使用延续?)

在论文中,延续在andalso (&&) 的右边,所以如果左边的操作数是False,它就会被丢弃。

在操作语义中,您可以将延续视为评估上下文,并且在该视图中丢弃延续对应于引发异常。当然可以,但关键是这需要源语言中的额外机制。

【讨论】:

    【解决方案2】:

    CPS 代码(在问题的原始版本中——自 OP 编辑​​后)似乎有问题。应该是这样的

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

    非 CPS 代码从中间开始比较,并进行 n `div` 2 比较,以获得长度为 n 的列表。即使发现不匹配,它也会继续测试,因此 “线性”

    在这种情况下,CPS 代码会立即退出,因为(False && undefined) == False 成立; “非线性”也是如此。两者等价,所以第一个没有说明第二个。

    正如the other answer 所说,不调用延续相当于在没有延续的代码中抛出异常,该论文的作者显然称之为“直接 [即,非CPS(?)--wn] 风格”。

    (我没看过论文)。

    顺便说一句,以“直接”风格对早期退出的解决方案进行编码一点也不难。我们将使用相同的海龟和兔子技巧来发现一半,同时反向构建前半部分,然后在 Haskell 中调用and $ zipWith (==) first_half_reversed second_half,或其等效的短路直接递归变体,使用严格的语言,例如方案。

    【讨论】:

    • 确实!在问题中解决它。 _不能被滥用
    • 或者在非便携式haskell特定代码and $ (==) <$> first_half_reversed <*> second_half我想
    • 并非没有一些ZipList 噪音。 :) 此外,更简单的代码通常更清晰。
    猜你喜欢
    • 2018-09-22
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多