Question

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) | 
Was it helpful?

Solution 2

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.

OTHER TIPS

Just for fun, I thought I'd throw together a solution with a very different flavor. Imagine for a moment that instead of a list of numbers, we had a string with an L when the numbers decreased, an E when they stayed the same, or a G when they got bigger. Then being triangular means testing whether that string is in the regular language [LE]*[GE]*. So that's what we'll do in this solution: write a regex and check whether the numbers' summary matches it. I'm using regex-applicative, but you can use your favorite regex library instead if you like.

{-# LANGUAGE NoMonomorphismRestriction #-}
import Data.Maybe
import Text.Regex.Applicative

triangular = many (sym LT <|> sym EQ) *> many (sym GT <|> sym EQ)
summarize xs = zipWith compare xs (tail xs)

ex = isJust . match triangular . summarize

We can try it on all your examples in ghci:

*Main> map ex [[2,4,5,7,4,3], [], [1], [1, 2, 3], [3, 2, 1], [1, 2, 2], [2, 2, 1]]
[True,True,True,True,True,True,True]
*Main> ex [2,3,4,3,2,3,4] -- plus one I made up to check it's not const True
False
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top