谓词和列表搜索haskell

时间:2017-01-07 16:45:35

标签: list haskell predicate

我正在学习Haskell,并且已经陷入停滞状态了。我正在尝试编写一个带谓词p和列表xs的函数,并返回xs的元素列表,这些元素紧跟在传递谓词{{1}的元素之后}}。这就是我所拥有的:

p

测试输入:afterFilter :: (a -> Bool) -> [a] -> [a] afterFilter x (y:ys) = if x y then (map head [ys]) else afterFilter x (tail ys)

输出:afterFilter (<0) [-4,7,-4,-8,3,-3,-6,0,-9,-1]

3 个答案:

答案 0 :(得分:4)

诀窍是通过模式匹配两个cons单元将两个元素从输入列表中拉出来。如果第一个元素通过谓词,我们将第二个元素粘贴在输出上。但是,在进行递归调用时,不要忘记将第二个元素放回输入列表中。

afterFilter :: (a -> Bool) -> [a] -> [a]
afterFilter f [] = []   -- input list is empty
afterFilter f [x] = []  -- input list has only one element - no "next element" to return
afterFilter f (x:y:xs) =
    let ys = afterFilter f (y:xs)
    in (if f x then y:ys else rest)

但是,更高级别 - 更多Haskellish - 解决问题的方法是将其分解为一系列操作。

  1. 使用zip将列表中的每个项目与其后面的元素配对,因此我们有(element, next)对的列表。
  2. 使用filter删除element未通过谓词的对。
  3. 使用map提取每个幸存对的next部分。
  4. 所以代码看起来像这样:

    pairWithSuccessors :: [a] -> [(a, a)]
    pairWithSuccessors xs = zip xs (tail xs)
    
    afterFilter :: (a -> Bool) -> [a] -> [a]
    afterFilter p xs =
        let withSuccessors = pairWithSuccessors xs (tail xs)
            filtered = filter (\(element, next) -> p element) withSuccessors
            filteredSuccessors = map (\(element, next) -> next) filtered
        in filteredSuccessors
    

    或者,用无点样式编写:

    afterFilter p = map snd . filter (p . fst) . pairWithSuccessors
    

    使用合成运算符构建的函数 .从右向左阅读:首先pairWithSuccessors,然后filter (p . fst),然后map snd结束结果。

    GHC擅长使用列表:在使用优化编译时,两种方法都应该生成大致相同的机器代码 - 也就是说,高级解决方案没有性能成本

答案 1 :(得分:1)

按照你所做的,你的代码有一些奇怪的东西:

map head [ys]非常奇怪,导致你的函数停止:在匹配谓词的第一个元素处,你的函数返回一个包含其直接后继的列表并在那里停止。您仍然需要处理列表的其余部分。

此外,根据您对问题的定义,每个作为传递谓词的项的后继项的项应该在结果数组上。我可能错了,但我理解的是afterFilter (<0) [-1, -1, 1]应该返回[-1, 1]

但是,您要通过致电tail ys来放弃您未检查的一个元素:您检查了y,但未检查head ys

最后,通过添加边缘案例,您可以获得以下内容:

afterFilter :: (a -> Bool) -> [a] -> [a]

afterFilter _ [] = []
afterFilter _ [_] = []
afterFilter x (y:ys@(z:zs)) =
    if x y
        then z : afterFilter x ys
    else
        afterFilter x ys

答案 2 :(得分:0)

尝试:

afterFilter :: (a -> Bool) -> [a] -> [a]
afterFilter p [] = []
afterFilter p [_] = []
afterFilter p (x1:x2:xs) 
  | p x1 = x2:rest
  | otherwise = rest
  where rest = afterFilter p (x2:xs)

或者

afterFilter' :: (a -> Bool) -> [a] -> [a]
afterFilter' p xs = map snd $ filter (\(x, _) -> p x) $ zip xs (tail xs)

或者

afterFilter'' :: (a -> Bool) -> [a] -> [a]
afterFilter'' p xs = [y | (x, y) <- zip xs (tail xs), p x]