假设我们想要列表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中是否有更短/更好的方法可以做到这么短的时间?
答案 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
或者您更喜欢哪个更清晰的定义。重要的是你把它包装在一个函数中。