布尔选择列表

时间:2012-02-06 12:16:46

标签: haskell

假设我们想要列表x的那些元素,列表y的相应元素是严格为正的。以下三种解决方案中的任何一种都有效:

let x = [1..4]
let y = [1, -1, 2, -2]

[ snd both | both <- zip (map (> 0) y) x, fst both ]

map snd $ filter fst $ zip (map (>0) y) x

sel :: [Bool] -> [a] -> [a]
sel [] _ = []
sel (True : xs) (y : ys) = y : sel xs ys
sel (False : xs) (y : ys) = sel xs ys

sel (map (> 0) y) x

然而,促使这一点的是,在R语言中,这可以像这样紧凑地编写:

x[y > 0]

并且考虑到在Haskell中是否有更短/更好的方法可以做到这么短的时间?

4 个答案:

答案 0 :(得分:10)

我不是哈克尔专家,但为什么不使用list comprehension

 [i | (i,j)  <-  zip x y, j > 0 ]

答案 1 :(得分:1)

如果您愿意使用语言扩展,我可以提供替代

{-# LANGUAGE ParallelListComp #-}

bfilter :: (b -> Bool) -> [a] -> [b] -> [a]
bfilter cond xs ys = [x | x <- xs | y <- ys, cond y]

Haskell中的任何内容都不会像R版本一样短,因为在R中,它是一种内置的语言,但在Haskell中它并不是。显然,设计R的人发现那里有充分的理由包含这样一个原语,但没有一个Haskell设计者发现那里有令人信服的理由在语言中包含这样的结构(并且它不会很好地适应,所以我完全赞同这个决定 - 它可能适合R,我不会知道那种语言。)

答案 2 :(得分:1)

zip x y >>= \(a,b) -> filter(const(b>0)) [a]

或毫无意义地使用Applicative ...

import Control.Applicative

zip x y >>= filter <$> const.(>0).snd <*> (:[]).fst

答案 3 :(得分:1)

正如Daniel Fischer所说,没有任何特殊的语法。

如果您要经常进行此操作,最好定义自己的单个可重用函数,而不是每次都手动组装列表推导或映射/过滤器链。 (您的sel未通过此测试,因为来电者必须单独应用map

所以

selectWhere :: [a] -> (a -> Bool) -> [b] -> [b]
selectWhere ys pred = map snd . filter (pred . fst) . zip ys
-- call it like this:  selectWhere y (> 0) x

或者您更喜欢哪个更清晰的定义。重要的是你把它包装在一个函数中。