list - 带有两个参数的 Haskell 列表过滤
问题描述
我必须编写一个函数,该函数使用一个产生的参数True
进行过滤,然后使用另一个产生的参数进行过滤False
我试过这个:
selectUnless :: (t -> Bool) -> (t -> Bool) -> [t] -> [t]
selectUnless fx gx (x:xs) = filter gx (filter fx (x:xs))
但我需要那个“不是 gx”的列表。
例如:
selectUnless (>= 2) (==2) [1,2,3,4] == [3,4]
selectUnless even odd [1..50] == [2,4..50]
解决方案
Haskell 有一个not :: Bool -> Bool
转换True
成的运算符,False
反之亦然。
问题当然不是gx
一个,而是一个函数。然而,我们可以构造一个函数,如:Bool
t -> Bool
\x -> not (gx x)
因此,这将适用not
于 的结果gx x
。或者我们可以使用(.) :: (b -> c) -> (a -> b) -> a -> c
,例如:
selectUnless :: (t -> Bool) -> (t -> Bool) -> [t] -> [t]
selectUnless fx gx = filter (not . gx) . filter fx
我们甚至可以使用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 (&&)
或者@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 (.)
请注意,您的原始代码无法处理空列表:实际上,您只(x:xs)
在函数中为列表指定了模式,而不是[]
. 然而,这里没有必要使用额外的模式,filter
已经可以处理空列表和非空列表。
推荐阅读
- ios - Swift 4.1:UIPickerView 的 SelectRow 不会引发委托 didSelectRow
- java - 如何加载 HTML 的全部内容 - Jsoup
- python - 如何从保存的预训练模型的h5文件中找到层数?
- reactjs - react-select中选项的禁用原因
- export-to-excel - jsreport html-to-excel 选项
- android - 如何在联系人上添加自定义按钮以使用我的应用程序打开?
- java - 如果一个成员离开聊天,如何向其他 Twilio Chat 成员发送通知?
- android - 向下滚动时 Android 更新 ListView
- python - 跨多个进程使用双端队列对象
- java - java.awt.Robot 在 macOS Mojave 下工作异常