matt
matt

Reputation: 2039

Haskell: Efficient accumulator

What is the best way to map across a list, using the result of each map as you go along, when your result is of a different type to the list.

for example

f :: Int -> Int -> String -> String

l = [1,2,3,4]

I would like to have something that walks along the list l and does:

f 1 2 [] = result1 => f 2 3 result1 = result2 => f 3 4 result3 ==> return result3.

I can sort of get this to work with a an accumulator, but it seems rather cumbersome. Is there a standard way to do this... or is this something for Monads??

Thanks!

NB the function above is just for illustration.

Upvotes: 1

Views: 1084

Answers (3)

גלעד ברקן
גלעד ברקן

Reputation: 23955

Of course, rather than zipping, you could pass along the previous element inside the fold's accumulator. For example:

l = [1,2,3,4]
f x y = (x,y)
g b@(accum,prev) a = (accum ++ [f prev a],a)

main = print (foldl g ([],head l) (tail l))

Output:

([(1,2),(2,3),(3,4)],4)

Upvotes: 1

amalloy
amalloy

Reputation: 91837

This is just a fold left over the pairs in the input list:

f :: Int -> Int -> String -> String
f = undefined

accum :: [Int] -> String
accum xs = foldl (flip . uncurry $ f) "" $ zip xs (drop 1 xs)

You probably want to use Data.List.foldl' instead of foldl, but this is an answer that works with just Prelude.

Upvotes: 4

fjarri
fjarri

Reputation: 9726

Seems like a job for fold:

func f l = foldl (\s (x, y) -> f x y s) "" (zip l (tail l))

-- just some placeholder function
f :: Int -> Int -> String -> String
f x y s = s ++ " " ++ show(x) ++ " " ++ show(y)

l = [1,2,3,4]

main = print $ func f l

prints:

" 1 2 2 3 3 4"

(if you can change the signature of f, you can get rid of the ugly lambda that rearranges arguments)

Upvotes: 3

Related Questions