Search code examples
listhaskellfunctional-programmingpattern-matchingfold

Haskell - using foldl or foldr instead of pattern matching for updating a list with a new value at a given index


I have implemented a function (!!=) that given a list and a tuple containing an index in the list and a new value, updates the given list with the new value at the given index.

(!!=) :: [a] -> (Int,a) -> [a]
(!!=) xs (0, a) = a : tail xs
(!!=) [] (i, a) = error "Index not in the list"
(!!=) (x:xs) (i, a) = x : xs !!= (i-1, a)

Being a beginner with the concept of folding I was wondering if there is a way to achieve the same result using foldl or foldr instead?

Thanks a lot in advance.


Solution

  • I'll give you the foldl version which is easier to understand I think and the easiest / most straight-forward version I can think of.

    But please note that you should not use foldl (use foldl': https://wiki.haskell.org/Foldr_Foldl_Foldl') - nor should you use ++ like this (use : and reverse after) ;)

    Anway this is the idea:

    (!!=) xs (i, a) = snd $ foldl 
       (\(j, ys) x -> (j+1, if j == i then ys ++ [a] else ys ++ [x])) 
       (0, []) 
       xs
    
    • as the state/accumulator for the fold I take a tuple of the current index and the accumulated result list (therefore the snd because I only want this in the end)
    • then the folding function just have to look if we are at the index and exchange the element - returning the next index and the new accumulated list

    as an exercise you can try to:

    • use : instead of ++ and a reverse
    • rewrite as foldr
    • look at zipWith and rewrite this using this (zipWith (...) [0..] xs) instead of the fold (this is similar to using a map with index