使用foldl / foldr从String中删除元素

时间:2017-11-06 20:05:44

标签: haskell

如果有可能我想使用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。有没有办法使用折叠功能?

2 个答案:

答案 0 :(得分:3)

foldr作为 catamorphism

我们可以在这里使用的一个方面是foldr是列表[]上的 catamorphism 。的确,我们可以写:

foldr (:) []

如果我们输入一个列表,我们将获得完全相同的列表:

Prelude> foldr (:) [] [1,4,2,5]
[1,4,2,5]

为什么呢?概念上foldr遍历列表从右到左。它使用首先为[]的累加器,对于列表x中的每个元素,它使用xa调用函数(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"