【问题标题】:How would I rewrite this palindrome verifier in point-free style?我将如何以无点风格重写这个回文验证器?
【发布时间】:2015-12-31 14:56:10
【问题描述】:

我有这段代码:

palindrome :: String -> Bool
palindrome x = x == reverse x

有没有什么方法可以用无点风格重写它?

【问题讨论】:

标签: haskell pointfree


【解决方案1】:

是的,因为任何函数都可以用无点样式编写。在这里,(->) r(又名 Reader)的 Applicative 实例为您执行此操作,因为

(f <*> g) x = f x (g x)

您可能会认出这是来自SKI calculus 的 S 组合子(顺便说一下,return 是 K)。

你的回文检查器写成

x == reverse x

中缀形式的读法

(==) x (reverse x)

与上面的&lt;*&gt; 定义相比,这导致了表达式

isPalindrome x = ((==) <*> reverse) x

您可以在其中删除尾随的 x 以获得解决方案

isPalindrome = (==) <*> reverse

这可能比原始表达式可读性差,因此不应使用。无点样式是为了可读性,并且仅在某些情况下有用。

【讨论】:

  • “这可能比原始表达式可读性差,因此不应使用”是一个有趣的评论。有些 Python 爱好者会争辩说,map 的可读性总是不如列表理解。可读性实际上取决于流行的习语。看惯了applicative style的人可能会把point-free的版本理解为“平等高于同一性和颠倒”之类的,这很容易理解。流行的成语随着时间的推移而变化,所以如果你想让它朝着特定的方向变化,你可以谨慎使用“奇怪”的成语。
  • @kqr 对,习惯于 Applicative (->) 使用的人对此代码没有问题。但是请注意,当您第一次了解基本应用程序 (->) 时,它的位置相当高。这里的代码很简单,但是可以写成只有中级程序员才能读懂的方式。
  • @David 是对的,但 &lt;*&gt;join 应该是 a basic repertoire for point-free style 的一部分,它可以自己学习(除了作为 Applicative 实例)。
【解决方案2】:

你可能认为这种方法是作弊:

palindrome :: Eq a => [a] -> Bool
palindrome = palindrome'
  where palindrome' xs = xs == reverse xs

当然还有 David 和 freyrs 建议的应用风格:

palindrome'' :: Eq a => [a] -> Bool
palindrome'' = (==) <*> reverse

但是这个表达式作为折叠怎么样?

palindrome''' :: Eq a => [a] -> Bool
palindrome''' = (foldl (\b (x, y) -> b && x == y) True)
              . (uncurry zip)
              . reverse'
  where reverse' xs = (xs, reverse xs)

【讨论】:

  • 虽然reverse' 不是无点的,所以你可以说这和你的第一个一样。要使reverse' 无点,您将再次需要应用版本,使其与您的第二个示例相同! (foldl lambda 也不是无点的,但我有一种感觉,它只是从 Data.List 重新实现了 all,因此可以快速使表达式变得无点。)
  • fold with (&amp;&amp;) 只是 and: palindrome = and . uncurry (zipWith (==)) . join ((,).reverse)。但当然and . uncurry (zipWith (==)) 只是uncurry (==) 的一个实现,正如the answer by swish 所举例说明的那样。 :)
【解决方案3】:

(-&gt;) r 也是一个 Monad,所以你的回文检查器可以用 monadic bind 编写,这可能比上面的 Applicative 解决方案更具可读性

palindrome :: String -> Bool
palindrome = reverse >>= (==)

【讨论】:

  • 附注:ap k g == g &gt;&gt;= (flip k) == k &lt;*&gt; g == \x -&gt; k x (x r)。所以你的代码表示reverse xs == xs
【解决方案4】:

是的。

palindrome :: String -> Bool
palindrome = ap (==) reverse

【讨论】:

    【解决方案5】:
     palindrome :: String -> Bool
     palindrome = uncurry (==) . (id &&& reverse)
    

    (&amp;&amp;&amp;)Control.Arrow 中定义,因此(f &amp;&amp;&amp; g) x = (f x, g x)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-31
      • 2013-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-11
      相关资源
      最近更新 更多