Home > Enterprise >  Remove the 'a' and 'A' characters from two lists and return them as a pair
Remove the 'a' and 'A' characters from two lists and return them as a pair

Time:10-22

Implement the filterA2 :: [Char] -> [Char] -> ([Char], [Char]) function that removes the characters 'a' and 'A' from both of the lists and returns the results as a pair.

For example:

filterA2 "Always" "runAway" == ("lwys", "runwy")

filterA2 "Cherry" "Tree" == ("Cherry", "Tree")

So far, I've tried:

filterA2 [] [] = ([], [])
filterA2 ['a'] ['a'] = ([], [])
filterA2 ['A'] ['A'] = ([], [])
filterA2 ['a'] [xs] = ([], [xs])
filterA2 [xs] ['a'] = ([xs], [])
filterA2 ['A'] [xs] = ([], [xs])
filterA2 [xs] ['A'] = ([xs], [])
filterA2 (x:xs) (y:ys) = filterA2 (xs) (ys)

Which always returns ("", "") no matter what I type. I might've used too much base cases.

CodePudding user response:

The problem with your approach is: your patterns only work if there are only one single character in each list...

filterA2 :: [Char] -> [Char] -> ([Char], [Char])
filterA2 l1 l2 = (remove l1, remove l2)
    where
        remove :: [Char] -> [Char]
        remove [] = []
        remove (x:xs)
            |x == 'A' || x == 'a' = remove xs
            | otherwise = x : remove xs

CodePudding user response:

import Data.Char (toLower)

filterA2 :: [Char] -> [Char] -> ([Char], [Char])
filterA2 [] [] = ([], [])
filterA2 (x:xs) []
  | toLower x == 'a'  = (xs', [])
  | otherwise         = (x:xs', []) where
    (xs', _)          = filterA2 xs []
filterA2 [] (y:ys)
  | toLower y == 'a'  = ([], ys')
  | otherwise         = ([], y:ys') where
    (_, ys')          = filterA2 [] ys
filterA2 (x:xs) (y:ys)
  | toLower x == 'a' && toLower y == 'a'  = (xs', ys')
  | toLower x == 'a'                      = (xs', y:ys')
  | toLower y == 'a'                      = (x:xs', ys)
  | otherwise                             = (x:xs', y:ys') where
    (xs', ys') = filterA2 xs ys

If you need to do it with explicit recursion and pattern matching, above is a way to do it using these methods. Of course, using built-in functions would make the code much simpler to implement and easier to read, but you are probably doing this for educational purposes.

There are 4 basic patterns as you can see and each of the has specific cases, implemented as guards, based on the pattern. The key idea is that each function return a tuple of 2 values that are returned from a recursive function call.

filterA2 (x:xs) (y:ys) = (x:xs', y:ys') where
  (xs', ys') = filterA2 xs ys

To put aside the guards and different cases and just see how we create the tuple. So, haskell's laziness aside, even if the code wanted to calculate as much as possible at each instant, it couldn't calculate the return value of a function, unless it had the return value from the recursive call below the stack. So, how this plays out is that the function goes down the recursive stack until it hits bottom where the base case pattern matches since both lists have become empty:

filterA2 [] [] = ([], [])

At this point, the lowest function returns its value and subsequently the function above it can also calculate and return its value and so forth up until the final result is returned.

  • Related