3

所以我有一个我想根据规则集过滤的项目(食谱)列表,

ruleset = [rule0, rule1, rule2, rule3, rule4]

其中每个规则都是一个函数 :: Recipe -> Bool。我想将这些规则应用于列表中的每个项目,我一直在使用以下函数:

testRules :: Recipe -> Bool
testRules r = rule0 r && rule1 r && rule2 r && rule3 r && rule4 r

必须有一种方法来应用数组而不明确说“rule0 && rule1&& ...”

有人知道方法吗?我知道'map' 将一个函数应用于列表.. 并且 zipWith 将一个数组乘以一个数组.. 必须有另一个函数来执行此任务!

我也一直在想,也许我可以将规则集作为参数传递给 testRules 并递归地遍历规则集:

testRules (rule:rules) r = rule r && testRules rules
testRules [] r = True

但是,我不知道如何提供函数的头部(testRules :: )

为任何帮助干杯!

4

5 回答 5

11

还有all :: (a -> Bool) -> [a] -> Bool可以使用的功能。此函数检查谓词是否适用于列表的所有值。

只是现在,我们要稍微扭转一下,让谓词是“当它应用于 x 时,这条规则的结果为真”,列表将包含谓词。

您可以将谓词表示为,\rule -> rule x == True但这与 相同\rule -> rule x,与 相同,\rule -> rule $ x与 相同($x)。所以这条思路给了我们很好的和简短的:

testRules :: [a -> Bool] -> a -> Bool
testRules rules x = all ($x) rules

这可以通过使用变得无意义,testRules = flip (all . flip ($))但我认为这有点过头了。

于 2012-10-09T16:53:32.083 回答
3

您可以使用and,它需要一个列表Bool并返回True如果所有这些都是True.

然后,将 zipWith 与应用程序 ($) 一起使用:

testRules :: [a -> Bool] -> a -> Bool
testRules :: and $ zipWith ($) ruleset (repeat r)
于 2012-10-09T16:19:00.380 回答
3

结合and列表推导很好地解决了这个问题:

testRules :: [Recipe -> Bool] -> Recipe -> Bool
testRules ruleSet r = and [rule r | rule <- ruleSet]
于 2012-10-09T17:00:13.357 回答
2

首先想到的是:

testRules :: Recipe -> [ Recipe -> Bool ] -> Bool
testRules r ruleset = and $ map (\rule -> rule r) ruleset
于 2012-10-09T16:03:40.350 回答
2

我相信有很多方法。我喜欢折叠(带有应用程序):

testRules = foldl1 (\f r -> (&&) <$> f <*> r) rules
于 2012-10-09T16:07:39.407 回答