Haskell中的snd函数如何在过滤器中工作

Jes*_*sse 3 haskell filtering predicate list filter

我将此代码输入ghci

Prelude> filter snd [('a',True),('b',True),('c',False),('d',True)]
Run Code Online (Sandbox Code Playgroud)

为什么返回

[('a',True),('b',True),('d',True)]
Run Code Online (Sandbox Code Playgroud)

而不是

[('a',True),('c',False),('d',True)]
Run Code Online (Sandbox Code Playgroud)

snd函数返回第二个项目,那么为什么不filter snd过滤第二个项目呢?

Han*_*Lub 8

您希望filter从该表达式的口语意义上 “过滤”出列表中的元素,从而filter snd 删除第二项。

那不是它的工作原理

如果您是对的,请filter snd [1,2,3]评估为[1,3]。相反,它不会像snd对元组(而不是数字)那样进行类型检查。

那么它是怎样工作的?

filter f [item1, item2, ...]返回所有列表itemS表示这f itemTrue

例如,filter even [1,2,3,4]返回[2,4]

作为snd ('b', True)对的评估True,您的示例filter中将包括(b, True)结果。同样,(c, False)将省略


Wil*_*sem 7

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

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

filter因此,过滤器的elementwise:它并没有考虑到列表中的下一个或前一个元素(一个或多个)。它只是检查元素上的谓词是否满足。

由于您在这里有一个2元组的列表,其中每个元组的第二个项目是a Bool,因此snd :: (a, b) -> b会将每个元素映射到第二个元素,因此保留2元组,其中2个元组的第二个项目是Truefilter snd因此filter snd :: [(a, Bool)] -> [(a, Bool)],最通用的类​​型是,因为2元组的第二项应为Bool

因此,这意味着filter snd确实将进行如下过滤:

Prelude> filter snd [('a',True),('b',True),('c',False),('d',True)]
[('a',True),('b',True),('d',True)]
Run Code Online (Sandbox Code Playgroud)

我们可以使用显式递归来过滤掉第二个元素,例如:

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

filterAtOdd :: [a] -> [a]
filterAtOdd [] = []
filterAtOdd (_:xs) = filterAtEven xs
Run Code Online (Sandbox Code Playgroud)

例如:

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)]
Run Code Online (Sandbox Code Playgroud)

或者,如果您要删除特定的索引,我们可以使用deleteAt :: Int -> [a] -> [a]ilist软件包:

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)]
Run Code Online (Sandbox Code Playgroud)

或者我们可以自己实现:

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
Run Code Online (Sandbox Code Playgroud)