3

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?

Wheat Wizard
  • 3,982
  • 14
  • 34
J. G.
  • 57
  • 5
  • Hey OP, I took the liberty to completely overhaul your question in order to keep it on-topic but also add some more examples for future readers. Feel free to [edit] stuff back in if you feel like I invalidated some of your concerns. – Zeta Feb 02 '21 at 09:05
  • 1
    I removed the solution which should be posted as a solution. Here on StackOverflow you are encouraged to post your own solution to your question whenever you feel like it. But we try to keep questions free of updates and/or solutions. Have a great time here. – Micha Wiedenmann Feb 02 '21 at 12:25

1 Answers1

7

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.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • the idea is nice... sorry for the lack of experience in haskell... but compiler just says "result" is not in scope. what should I do. – J. G. Feb 02 '21 at 09:14
  • 1
    @J.G. Make sure that all lines are indented the same. Also, make sure that you have `result = …` filled out correctly. – Zeta Feb 02 '21 at 09:18