Search code examples
listhaskellfoldleft

How can I count the number of times an element is greater than its successor?


I'm currently trying to solve the following exercise:

Given a list of Ints, count the number of times, an element is greater than the element that comes after it. The exercise forces me not to use explicit recursions.

Here are some example outputs given function :: [Int] -> Int:

function [1, 2, 3, 4, 5]         == 0  -- only increasing numbers
function [5, 4, 3, 2, 1]         == 4  -- only decreasing numbers

function [2,  1,  3,  1,  0,  4] == 3
--        2 > 1  
--                3 > 1
--                    1 > 0

function [1] == 0 -- no successor
function [ ] == 0 -- no numbers at all

I imagined to use in some way foldl but after many attempts and not working idea I had to give up.

How can I count the number of times an element is greater than its successor without using recursion?


Solution

  • First we need to pair up the consecutive elements,

    foo :: [Int] -> Int
    foo xs = result
      where
          pairs = zip xs (drop 1 xs)
    

    then we can process each pair

          biggers = [ () | (x,y) <- pairs, x > y]
    

    and now we can count them,

          result = .......
    

    All the nested names belong to the same, shared, nested scope. result must make use of the value of biggers, and biggers refers to the value of pairs which refers to the value of foo's parameter, xs. Make sure to put these code lines into the same definition, all indented by the same amount as the first one, for pairs, one under the other.


    Actually using a left fold is also possible:

    foo (h:t) = snd ( foldl' (\ (a, !c) x -> (x, if (a > x) then (c+1) else c)) 
                             (h,0) t )
    foo [] = 0
    

    I think you'll agree though that this is much less self-apparent than the first definition. Also note that it uses a "bang pattern", !, together with foldl', not foldl, to do the counting as soon as possible as we go along the input list, not delaying it until all the input list is traversed in full as foldl would do, needlessly, harming the overall efficiency.