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 item
是 True
例如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
。如果 Bool
是 True
它将在结果中保留原始列表的元素,否则该元素将不会成为结果的一部分。
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
我将此代码输入到 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 item
是 True
例如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
。如果 Bool
是 True
它将在结果中保留原始列表的元素,否则该元素将不会成为结果的一部分。
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