2

考虑一下:

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

其中rule0,rule1等是带有一个参数的布尔函数。查找特定列表的所有元素是否满足所有规则的最简洁方法是ruleset什么?

显然,循环是可行的,但 Haskell 的人似乎总是对这些类型的问题有聪明的单线。

all函数似乎合适(例如all (== check_one_element) ruleset)或嵌套maps。此外,map ($ anElement) ruleset这大致是我想要的,但适用于所有元素。

我是 Haskell 的新手,解决这个问题的方法有很多。

4

4 回答 4

12

如果您要求每个参数的所有函数都为真,那么它只是

and (ruleset <*> list)

(您需要import Control.Applicative使用<*>.)

解释:

<*>给定一对列表时,它将左侧列表中的每个函数应用于右侧列表中的每个参数,并返回一个包含所有结果的列表。

于 2013-02-09T20:05:04.337 回答
3

单线:

import Control.Monad.Reader

-- sample data
rulesetL = [ (== 1), (>= 2), (<= 3) ]
list = [1..10]

result = and $ concatMap (sequence rulesetL) list

(我们在这里处理的类型是Integer,但也可以是其他类型。)

让我解释一下发生了什么:rulesetL是 type [Integer -> Bool]。通过意识到这(->) e是一个单子,我们可以使用

sequence :: Monad m => [m a] -> m [a]

在我们的例子中,它将专门用于 type [Integer -> Bool] -> (Integer -> [Bool])。所以

sequence rulesetL :: Integer -> [Bool]

将值传递给列表中的所有规则。接下来,我们使用concatMap此函数将所有结果应用于list并将所有结果收集到一个列表中。最后,调用

and :: [Bool] -> Bool

将检查返回的所有组合True

编辑:查看dave4420的答案,它更好更简洁。如果您需要组合规则并稍后在某些列表中应用它们,我的回答可能会有所帮助。尤其

liftM and . sequence :: [a -> Bool] -> (a -> Bool)

将多个规则合二为一。您还可以将其扩展到其他类似的组合器,例如 usingor等。意识到规则是(->) amonad 的值可以为您提供其他有用的组合器,例如:

andRules = liftM2 (&&) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
orRules  = liftM2 (||) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
notRule  = liftM not :: (a -> Bool) -> (a -> Bool)
         -- or just (not .)

等(不要忘记导入Control.Monad.Reader)。

于 2013-02-09T20:15:04.967 回答
1

一个更容易理解的版本(不使用Control.Applicative):

satisfyAll elems ruleset = and $ map (\x -> all ($ x) ruleset) elems
于 2013-02-09T20:07:40.587 回答
1

就个人而言,我喜欢这种编写函数的方式,因为它明确使用的唯一组合器是and

allOkay ruleset items = and [rule item | rule <- ruleset, item <- items]
于 2013-02-10T07:45:21.877 回答