使用高阶函数和 Lambda 微积分在 Haskell 中操作列表

Manipulating Lists in Haskell using Higher-Order Functions and Lambda Calculus

我正在尝试编写一个非常简单的函数,它接受一个列表(例如:[1,2,3,1,5])和 returns 紧接在特定元素之后的元素列表。

到目前为止我达到的是:

function element list = filter (\x -> element:x) list

我想要的输出:

function 1 [1,2,3,1,5]

=>   [2,5]

试试这个

map snd $ filter ((== x) . fst) $ zip theList (tail theList)

这不适用于空列表,您仍然需要额外的代码来处理它。


这是如何工作的?

首先,请注意值是从右向左流动的。 ($) 运算符允许这种情况发生。因此,评估的第一部分是 zip 函数。

zip theList (tail theList)

对于上面的示例,这将产生

zip [1,2,3,1,5] [2,3,1,5]

等于

[(1,2), (2, 3), (3, 1), (1,5)]

这是列表中并发对的集合。

接下来,应用过滤器

filter ((== x) . fst) $ ....

英文的意思是,只过滤掉第一个元素等于x的并发对。输出是

[(1,2), (1,5)]

现在我们有了以 1.

开头的并发对列表

最后,我们应用地图

map snd $ ....

这只是提取了该对的第二个值。

map snd [(1,2), (1,5)] = [2,5]

这是想要的值。


请注意,我上面关于空列表失败的评论。

这是因为 tail 在空列表上崩溃

tail [] --error

有很多方法可以修补此行为(例如,请参阅 safe 包),但此时主要是簿记,所以我把它留给你解决。


另请注意,由于我们使用的所有函数都是惰性函数,因此这种方法也适用于无限长度的列表。

您可以通过简单的列表理解轻松地做到这一点,例如:

successors xs i = [y | (x,y) <- zip xs (drop 1 xs), x == i]

这将符合您的要求

next x (i:y:ys) -- look at the first two items in the list
    | x == i = -- if the first item == x, 
        y : next x (y:ys) -- take the second, and continue minus the first element
    |otherwise = -- not equal, 
        next x (y:ys) -- so skip that element
next _ [_] = [] -- if there's no second element, then stop
next _ _ = [] -- if the list is empty, stop