将清单函数列表应用于列表的最简洁方法?

时间:2013-02-09 19:54:24

标签: haskell

考虑一下:

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

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

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

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

我是Haskell的新手,人们可以解决这个问题的方法很多。

4 个答案:

答案 0 :(得分:12)

如果您需要所有 每个参数的函数,那么它只是

and (ruleset <*> list)

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

说明:

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

答案 1 :(得分:3)

单行:

import Control.Monad.Reader

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

result = and $ concatMap (sequence rulesetL) list

(我们在这里工作的类型是Integer,但它可能是其他任何内容。)

让我解释一下发生了什么:rulesetL的类型为[Integer -> Bool]。通过认识(->) e是monad,我们可以使用

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

在我们的案例中将专门输入[Integer -> Bool] -> (Integer -> [Bool])。所以

sequence rulesetL :: Integer -> [Bool]

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

and :: [Bool] -> Bool

将检查所有组合是否返回True

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

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

将多个规则合并为一个。您还可以将其扩展到其他类似的组合器,例如使用or等。实现规则是(->) a monad的值可以为您提供其他有用的组合器,例如:

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)。

答案 2 :(得分:1)

易于理解的版本(不使用Control.Applicative):

satisfyAll elems ruleset = and $ map (\x -> all ($ x) ruleset) elems

答案 3 :(得分:1)

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

allOkay ruleset items = and [rule item | rule <- ruleset, item <- items]