【发布时间】:2014-05-07 13:07:10
【问题描述】:
是否可以在以下情况下应用 eta 减少?
let normalise = filter (\x -> Data.Char.isLetter x || Data.Char.isSpace x )
我期待这样的事情是可能的:
let normalise = filter (Data.Char.isLetter || Data.Char.isSpace)
...但事实并非如此
【问题讨论】:
是否可以在以下情况下应用 eta 减少?
let normalise = filter (\x -> Data.Char.isLetter x || Data.Char.isSpace x )
我期待这样的事情是可能的:
let normalise = filter (Data.Char.isLetter || Data.Char.isSpace)
...但事实并非如此
【问题讨论】:
您的解决方案不起作用,因为(||) 适用于Bool 值,而Data.Char.isLetter 和Data.Char.isSpace 的类型为Char -> Bool。
pl 给你:
$ pl "f x = a x || b x"
f = liftM2 (||) a b
解释:liftM2 将(||) 提升为(->) r monad,所以它的新类型是(r -> Bool) -> (r -> Bool) -> (r -> Bool)。
所以在你的情况下,我们会得到:
import Control.Monad
let normalise = filter (liftM2 (||) Data.Char.isLetter Data.Char.isSpace)
【讨论】:
(<||>) = liftM2 (||),然后您可以将其用作filter (isLetter <||> isSpace),甚至可以像filter (isLetter <||> isSpace <||> (== '1'))一样继续组合它们。我发现这种风格特别容易使用和吸引人。
import Control.Applicative
let normalise = filter ((||) <$> Data.Char.isLetter <*> Data.Char.isSpace)
【讨论】:
另一个值得研究的解决方案涉及箭头!
import Control.Arrow
normalize = filter $ uncurry (||) . (isLetter &&& isSpace)
&&& 采用两个函数(实际上是箭头)并将它们的结果压缩到一个元组中。然后我们只是取消||,所以是时候变成(Bool, Bool) -> Bool了,我们都完成了!
【讨论】:
您可以利用Any monoid 和返回 monoid 值的函数的 monoid 实例:
import Data.Monoid
import Data.Char
let normalise = filter (getAny . ((Any . isLetter) `mappend` (Any . isSpace)))
【讨论】: