xen*_*rin 0 haskell list filter
我必须编写一个函数,该函数使用结果一个参数True过滤,然后使用结果另一个参数过滤False
我尝试了这个:
selectUnless :: (t -> Bool) -> (t -> Bool) -> [t] -> [t]
selectUnless fx gx (x:xs) = filter gx (filter fx (x:xs))
Run Code Online (Sandbox Code Playgroud)
但是我需要“ not gx”所在的列表。
例如:
selectUnless (>= 2) (==2) [1,2,3,4] == [3,4]
selectUnless even odd [1..50] == [2,4..50]
Run Code Online (Sandbox Code Playgroud)
Haskell有一个not :: Bool -> Bool运算符,可以转换True为False,反之亦然。
问题当然是的gx是不是一个Bool,而是一个功能t -> Bool。但是,我们可以构造如下函数:
\x -> not (gx x)
Run Code Online (Sandbox Code Playgroud)
因此,这将适用not于的结果gx x。或者我们可以使用(.) :: (b -> c) -> (a -> b) -> a -> c,例如:
selectUnless :: (t -> Bool) -> (t -> Bool) -> [t] -> [t]
selectUnless fx gx = filter (not . gx) . filter fxRun Code Online (Sandbox Code Playgroud)
我们甚至可以使用liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c以下方法使之完全没有意义:
import Control.Applicative(liftA2)
selectUnless :: (t -> Bool) -> (t -> Bool) -> [t] -> [t]
selectUnless = (filter .) . (. (not .)) . liftA2 (&&)Run Code Online (Sandbox Code Playgroud)
或@JonPurdy提供的更优雅的解决方案:
import Control.Applicative(liftA2)
import Data.Function(on)
pre :: (a -> b) -> (b -> c) -> a -> c
pre = flip (.)
filtered :: (([a] -> [a]) -> ([a] -> [a]) -> c) -> (a -> Bool) -> (a -> Bool) -> c
filtered = (`on` filter)
selectUnless :: (a -> Bool) -> (a -> Bool) -> [a] -> [a]
selectUnless = pre (not .) . filtered (.)Run Code Online (Sandbox Code Playgroud)
请注意,您的原始代码无法处理空列表:实际上,您仅(x:xs)在函数中为列表指定了模式,而没有指定[]。但是没有必要在这里使用额外的模式,因为filter已经可以处理空列表和非空列表。