Search code examples
listhaskellghcitriangular

Triangular Lists in Haskell?


I have to write a function (without using preloaded functions) that decides if a certain list of Ints is triangular or not, and by triangular I mean if it increases up to a certain number and then decreases, for example:

[2,4,5,7,4,3] but also: [], [1], [1,1], [1, 2, 3], [3, 2, 1], [1, 2, 2], [2, 2, 1] (so non-strict increasing and decreasing)

I came up with this but I dont know what to do next, any advice is appreciated:

ex :: [Int] -> Bool
ex [] = True
ex (x:xs) | 

Solution

  • I’ll try to explain you some code while I develop it. The problem can obviously be split in two: Detecting the increasing part of the list, and the decreasing part of a list. The key idea of working with lists in Haskell is that you (if you don’t already have the empty list at hand) always look at the head of the list, and the tail, and you usually try to go through the list in that order.

    So let us write a function that detect whether a list is non-strictly decreasing first. There are of course several ways, to do this. Let’s try a recursive approach that does without extra parameters. You already had a good start

    dec :: [Int] -> Bool
    dec [] = True
    

    now lets continue pattern matching. The next largest list that is not empty is the list with one element, which is obviously always decreasing:

    dec [x] = True
    

    the next step is interesting. If we have a list with two elements (x and y) at the beginning (and possibly more) then for the list to de decreasing, clearly x >= y needs to hold, but also the remaining list, starting at y, needs to be decreasing. As that is sufficient, we just have to write it out

    dec (x:y:rest) = x >= y && dec (y:res)
    

    And thats it!

    Now to your exercise function, where can do the same thing. The only difference is once the list fails to be increasing, we allow check if the the list might be decreasing from this point on:

    ex :: [Int] -> Bool
    ex [] = True
    ex [x] = True
    ex (x:y:rest) = (x <= y && ex (y:res)) || dec (x:y:rest)
    

    I hope the explanation of how I came to write that code helps you with your next exercises. Also note that there are many other, also more efficient, ways to solve this.