5

我有这段代码:

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

有没有办法以无点风格重写它?

4

5 回答 5

8

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

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

您可能会认为这是SKI 演算中的 S 组合子(return顺便说一下是 K)。

你的回文检查器写成

x == reverse x

中缀形式为

(==) x (reverse x)

并且与<*>上面的定义相比,这导致了表达式

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

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

isPalindrome = (==) <*> reverse

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

于 2013-10-13T19:59:51.660 回答
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)
于 2013-10-13T20:24:13.790 回答
2

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

palindrome :: String -> Bool
palindrome = reverse >>= (==)
于 2013-10-14T04:22:01.800 回答
1
 palindrome :: String -> Bool
 palindrome = uncurry (==) . (id &&& reverse)

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

于 2013-10-13T22:03:24.173 回答
1

是的。

palindrome :: String -> Bool
palindrome = ap (==) reverse
于 2013-10-13T19:50:30.803 回答