Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - filter string list based on some conditions

I am new in this comunity. I learn Haskell and have difficulties with Haskell-coding. I hope you can help me.

I searched here and in Google, without any success.

My problem ist as fowllows: I want to write a function which takes a list as parameter like this:

myStringListFilter :: [String] -> [String]

process the following steps:

  1. Remove the first letter

    myStringListFilter myList = map tail strListe myList
    
  2. Filter every element in the list which begins with "u" or "U".

    myStringListFilter myList = filter (´elem´ ['u', 'U']) (map tail strListe myList)
    

Step two doesn't work. I get error.

How do I achieve the solution, if I want the following:

Input: ["butter", "chees", "aUbergine", "egg", "milk", "bUbble", "curry"]

Output: ["chees", "egg", "milk"]
like image 594
John Avatar asked Dec 09 '22 15:12

John


1 Answers

The type of filter is

filter :: (a -> Bool) -> [a] -> [a]

so if you want to filter a list of Strings according to a predicate, you need a function String -> Bool, but what you wrote, (`elem` ['u',U']) has type Char -> Bool.

So you need a function

beginsWithU :: String -> Bool

the easiest way to define it is

beginsWithU (c:_) = c == 'u' || c == 'U'
beginsWithU _ = False                      -- empty list

Then you have misunderstood how filter works, it keeps the elements satisfying the predicate, you want to remove them, so you need to compose the predicate with a not (or define as doesn'tbeginWithU directly).

However, as 7stud points out, you do not actually want to change the elements you want to keep from the original list, what

myStringListFilter myList = filter (not . beginsWithU) (map tail myList)

or, point-free:

myStringListFilter = filter (not . beginsWithU) . map tail

would achieve. So you need to incorporate the tail into the predicate too, and need no map, that would yield

myStringListFilter = filter (not . beginsWithU . tail)

or, if the possibility that an empty String occurs in the input list shall be dealt with benignly,

myStringListFilter = filter (not . beginsWith . drop 1)

since tail "" would produce an *** Exception: Prelude.tail: empty list whereas drop 1 "" produces "".

But, as you want to keep the original list element, you can also define the predicate to directly look at the second character,

secondCharIsU :: String -> Bool
secondCharIsU (_:c:_) = c == 'u' || c == 'U'
secondCharIsU _       = False

myStringListFilter = filter (not . secondCharIsU)
like image 199
Daniel Fischer Avatar answered Dec 11 '22 10:12

Daniel Fischer