如果有可能我想使用foldl或foldr从字符串['A'..'Z']中删除字符'A','T','C'和'G'
我试过了:
string = ['A'..'Z']
test string = foldl (\string (x:xs) ->
if x == 'A' then drop ('A' string)
else test xs) string
然而它不起作用,因为drop不适用于Char。有没有办法使用折叠功能?
答案 0 :(得分:3)
foldr
作为 catamorphism 我们可以在这里使用的一个方面是foldr
是列表[]
上的 catamorphism 。的确,我们可以写:
foldr (:) []
如果我们输入一个列表,我们将获得完全相同的列表:
Prelude> foldr (:) [] [1,4,2,5]
[1,4,2,5]
为什么呢?概念上foldr
遍历列表从右到左。它使用首先为[]
的累加器,对于列表x
中的每个元素,它使用x
和a
调用函数(a
为累加器作为论点。在新累加器中获得的结果用于处理新元素。
所以:
foldr (:) [] [1,4,2,5]
-> foldr (:) ((:) 5 []) [1,4,2]
现在(:)
是一个构造函数,它接受 head (此处为5
)和一个尾部(此处为[]
),并构造一个以头部作为第一个元素,后跟尾部元素,因此(:) 5 []
等于[5]
。
-> foldr (:) [5] [1,4,2]
-> foldr (:) [2,5] [1,4]
-> foldr (:) [4,2,5] [1]
-> foldr (:) [1,4,2,5] []
-> [1,4,2,5]
因此,如果我们通过foldr (:) []
传递列表,我们会获得相同的列表。
这与我们的问题有什么关系?好吧,如果我们想要执行过滤,我们可以使用另一个函数而不是(:)
。我们应该只在字符不是'A'
,'C'
,'G'
或'T'
时添加前缀。所以一些功能适用于:
f x xs | <some-condition> = x : xs
| otherwise = xs
现在,为了检查某个字符x
是不是'A'
,'C'
,'G'
还是'T'
,我们可以写一下:
not (elem x "ACGT")
所以现在的功能是:
f x xs | not (elem x "ACGT") = x : xs
| otherwise = x:xs
或更短:
f x | not (elem x "ACGT") = (x:)
| otherwise = id
我们也可以交换输出,从而删除not
:
f x | elem x "ACGT" = id
| otherwise = (x:)
因此,现在我们可以使用该函数f
代替(:)
和where
子句:
filterAcgt :: [Char] -> [Char]
filterAcgt = foldr f []
where f x | elem x "ACGT" = id
| otherwise = (x:)
现在我们可以生成一系列'A'..'Z'
,而不是'A'
,'C'
,'G'
和'T'
:
Prelude> filterAcgt ['A'..'Z']
"BDEFHIJKLMNOPQRSUVWXYZ"
答案 1 :(得分:0)
可能你可以这样做;
Prelude> foldr (\c a -> if (elem c $ "ATCG") then a else c : a) "" ['A'..'Z']
"BDEFHIJKLMNOPQRSUVWXYZ"