Home > OS >  Modify element in a list by adding the values of the next two elements in that list in Haskell
Modify element in a list by adding the values of the next two elements in that list in Haskell

Time:11-18

I am wanting to write a function to modify certain elements in a list only if they are a certain value.

For example, for every number that equals 10, I want to add the next two numbers in the list to that original number. So if I have: [10, 9, 1, 8, 2, 10, 10, 6, 4, 5, 4, 7, 3, 3, 4, 3, 7, 1]

then I want a function that will return: [20, 9, 1, 8, 2, 26, 20, 6, 4, 5, 4, 7, 3, 3, 4, 3, 7, 1]

I have explored using maps to do this, but I don't see how I can get a map to use the next two elements in the list to add them to the element that I want to modify.

This is my code so far. I know its obviously flawed by reusing the unchanging values of x:y:z

bowling :: [Int] -> [Int]
bowling (x:y:z:xs) = map (\x -> if (x == 10) then x   y   z else x) xs

b1 = bowling [10, 9, 1, 8, 2, 10, 10, 6, 4, 5, 4, 7, 3, 3, 4, 3, 7, 1]

I tried using maps to solve the problem, but I don't know how to create a function that will use the next two elements in the list.

CodePudding user response:

This is indeed impossible with just map. You can do it with explicit recursion, though, like this:

bowling :: [Int] -> [Int]
bowling [] = []
bowling (x:xs) = case x of
    10 -> case xs of
        y:z:_ -> x   y   z:bowling xs
        _ -> error "Uh oh, got a 10 but one or both of the next two numbers to add were missing"
    _ -> x:bowling xs

If you really want to do this with higher-order functions, you could use mapAccumR or para to do so instead. For example, with mapAccumR:

import Data.Traversable (mapAccumR)

bowling :: [Int] -> [Int]
bowling = snd . mapAccumR go (uhoh,uhoh) where
  go :: (Int,Int) -> Int -> ((Int,Int), Int)
  go ~(y,z) x = ((x,y), if x == 10 then x y z else x)
  uhoh :: Int
  uhoh = error "Uh oh, got a 10 but one or both of the next two numbers to add were missing"
  • Related