Home > Enterprise >  create a function ved that will only remove the last occurrence of the largest item in the list usin
create a function ved that will only remove the last occurrence of the largest item in the list usin

Time:10-16

You must use recursion to define rmax2 and you must do so from “scratch”. That is, other than the cons operator, head, tail, and comparisons, you should not use any functions from the Haskell library.

I created a function that removes all instances of the largest item, using list comprehension. How do I remove the last instance of the largest number using recursion?

ved :: Ord a => [a] -> [a]
ved [] =[]
ved as = [ a | a <- as, m /= a ]
  where m= maximum as

CodePudding user response:

If you are strictly required to use recursion, you can use 2 helper functions: One to reverse the list and the second to remove the first largest while reversing the reversed list.

This result in a list where the last occurrence of the largest element is removed.

We also use a boolean flag to make sure we don't remove more than one element.

This is ugly code and I really don't like it. A way to make things cleaner would be to move the reversal of the list to a helper function outside of the current function so that there is only one helper function to the main function. Another way is to use the built-in reverse function and use recursion only for the removal.

removeLastLargest :: Ord a => [a] -> [a]
removeLastLargest xs = go (maximum xs) [] xs where
  go n xs []     = go' n True [] xs
  go n xs (y:ys) = go n (y:xs) ys
  go' n f xs []  = xs
  go' n f xs (y:ys)
    | f && y == n = go' n False xs ys
    | otherwise   = go' n f (y:xs) ys

CodePudding user response:

Borrowing the implementation of dropWhileEnd from Hackage, we can implement a helper function splitWhileEnd:

splitWhileEnd :: (a -> Bool) -> [a] -> ([a], [a])
splitWhileEnd p = foldr (\x (xs, ys) -> if p x && null xs then ([], x:ys) else (x:xs, ys)) ([],[])

splitWhileEnd splits a list according to a predictor from the end. For example:

ghci> xs = [1,2,3,4,3,2,4,3,2]
ghci> splitWhileEnd (< maximum xs) xs
([1,2,3,4,3,2,4],[3,2])

With this helper function, you can write ven as:

ven :: Ord a => [a] -> [a]
ven xs = 
    let (x, y) = splitWhileEnd (< maximum xs) xs
     in init x    y

ghci> ven xs
[1,2,3,4,3,2,3,2]

For your case, you can refactor splitWhileEnd as:

fun p = \x (xs, ys) -> if p x && null xs then ([], x:ys) else (x:xs, ys)
splitWhileEnd' p [] = ([], [])
splitWhileEnd' p (x : xs) = fun p x (splitWhileEnd' p xs)

ven' xs = let (x, y) = splitWhileEnd' (< maximum xs) xs in init x    y

If init and are not allowed, you can implement them manually. It's easy!

BTW, I guess this may be your homework for Haskell course. I think it's ridiculous if your teacher gives the limitations. Who is programming from scratch nowadays?

Anyway, you can always work around this kind of limitations by reimplementing the built-in function manually. Good luck!

  • Related