我有这段代码:
palindrome :: String -> Bool
palindrome x = x == reverse x
有没有办法以无点风格重写它?
是的,因为任何函数都可以用无点样式编写。在这里,(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
这可能比原始表达式可读性差,因此不应使用。无点样式是为了可读性,并且仅在某些情况下有用。
你可能会认为这种方法是作弊:
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)
(->) r
也是一个 Monad,所以你的回文检查器可以用 monadic bind 编写,这可能比上面的 Applicative 解决方案更具可读性
palindrome :: String -> Bool
palindrome = reverse >>= (==)
palindrome :: String -> Bool
palindrome = uncurry (==) . (id &&& reverse)
(&&&)
在Control.Arrow中定义,因此(f &&& g) x = (f x, g x)
.
是的。
palindrome :: String -> Bool
palindrome = ap (==) reverse