function 和 in Haskell 如何在过滤器中工作

How function snd in Haskell works in filter

我将此代码输入到 ghci

Prelude> filter snd [('a',True),('b',True),('c',False),('d',True)]

为什么 returns

[('a',True),('b',True),('d',True)]

而不是

[('a',True),('c',False),('d',True)]

snd函数returns第二项,为什么不filter snd过滤第二项?

您的 filter 函数根据每对的第二个值过滤您的列表。这就是 ('c',False) 被过滤掉的原因...

您希望该表达式的 colloquial sense 中的列表中有 filter 到 "filter out" 个元素,因此 filter snd 删除第二个项目。

这不是它的工作原理

如果您是对的,filter snd [1,2,3] 的计算结果将是 [1,3]。相反,它不进行类型检查,因为 snd 适用于元组,而不适用于数字。

那么,它是如何工作的?

filter f [item1, item2, ...] returns 所有 item 的列表,其中 f itemTrue

例如filter even [1,2,3,4]returns[2,4]

由于 snd ('b', True) 的计算结果为 True,在您的示例中 filter 将在结果中包含 (b, True)。同样的道理,(c, False)也会被省略

简而言之filter snd保留二元组,其中元组的第二项是True.

filter :: (a -> Bool) -> [a] -> [a] 将一个函数作为参数,该函数将类型 a 的元素映射到 Bool。如果 BoolTrue 它将在结果中保留原始列表的元素,否则该元素将不会成为结果的一部分。

filter 因此过滤 elementwise:它确实 not 考虑下一个或前一个元素列表。它只是检查元素上的谓词是否满足。

因为你这里有一个双元组列表,其中每个元组的第二项是 Bool,因此 snd :: (a, b) -> b 将把每个元素映射到第二个元素上,从而保留 2 -元组,其中二元组的第二项是 True。因此,最通用的 filter snd 类型是 filter snd :: [(a, Bool)] -> [(a, Bool)],因为二元组的第二项应该是 Bool.

这意味着 filter snd 确实会像这样过滤:

Prelude> filter snd [('a',True),('b',True),('c',False),('d',True)]
[('a',True),('b',True),('d',True)]

我们可以用显式递归过滤掉每隔一个元素,例如:

filterAtEven :: [a] -> [a]
filterAtEven [] = []
filterAtEven (x:xs) = x : filterAtOdd xs

filterAtOdd :: [a] -> [a]
filterAtOdd [] = []
filterAtOdd (_:xs) = filterAtEven xs

例如:

Prelude> filterAtEven [('a',True),('b',True),('c',False),('d',True)]
[('a',True),('c',False)]
Prelude> filterAtOdd [('a',True),('b',True),('c',False),('d',True)]
[('b',True),('d',True)]

或者如果你想删除一个特定的索引,我们可以使用deleteAt :: Int -> [a] -> [a] of the ilist package:

Prelude> import Data.List.Index
Prelude Data.List.Index> deleteAt 2 [('a',True),('b',True),('c',False),('d',True)]
[('a',True),('b',True),('d',True)]

或者我们可以自己实现:

deleteAt :: Int -> [a] -> [a]
deleteAt i | i < 0 = id
           | otherwise = go i
  where go _ [] = []
        go 0 (_:xs) = xs
        go n (x:xs) = x : go (n-1) xs