Ohad
Ohad

Reputation: 1651

making a program with foldr function

Assuming that I have this function:

 sales::Int->Int

this function returns the number of sales in a specific week,the weeks are organized as a series 0,1,2.... (it gets the number of week and return the number of sales in that week)

I need to define the function zeroWeeks : zeroWeeks gets an integer n and returns number of weeks that has 0 sales in range [0...n]. (list of weeks)

I have solved it with list comprehension,

this is how I solved it with list comprehension:

zeroWeeks:: Int -> Int
zeroWeeks n = length(ans)
              where ans = [w|w<-[0..n],sales w==0]

How can I solve it with foldr function and without using recursion ?

Upvotes: 1

Views: 306

Answers (2)

hugomg
hugomg

Reputation: 69994

I think its a good idea to look how your function would look like using manual recursion instead of list comprehensions:

zeroWeeks :: [Int] -> Int
zeroWeeks [] = 0
zeroWeeks (x:xs) = (if sales x == 0 then 1 else 0)  + zeroWeeks xs

Now, lets look at how foldr is defined

foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)

As you can see, foldr is kind a high level pattern for defining functions similar oto zeroWeeks, with z standing in for the base case and f standing in for the operation we do in the recursive case. In zeroWeeks's case, its easy to see that we want to make z to be 0 and the tricky part is finding the f. Basically, what we need to do is make the x and zeroWeeks xs as explicit parameters instead of parts of a biggger expression:

zeroWeeks (x:xs) = (\x sum -> (if sales x == 0 then sum + 1 else sum)) x (zeroSum xs)

The end result is thus

zeroSum xs = foldr (\x sum -> (if sales x == 0 then sum + 1 else sum)) 0 xs

Although I would highly recommend refactoring that big lambda function into a separate functions for readability, like Benjamin Kovach did in his answer.

Upvotes: 1

Benjamin Kovach
Benjamin Kovach

Reputation: 3260

You can define a helper function f that returns 1 if there were 0 sales for some week, and 0 otherwise. Then you can compose + and f to map "zero weeks" to 1 and everything else to 0, then take the sum.

zeroWeeks :: [Int] -> Int
zeroWeeks = foldr ((+) . f) 0
  where f w | sales w == 0 = 1
            | otherwise = 0

Upvotes: 1

Related Questions