-1

I'm trying to make a function working out (and then outputting as a String) the difference between two elements in a list - 1st and 2nd, then 2nd and 3rd, and so on - I think I'm giving it a good go, but I currently keep running into error whack-a-mole, I've put the current error below, but first, obligatory code dump:

type Name = String
type Coordinates = (Int, Int)
type Pop = Int
type TotalPop = [Pop]
type City = (Name, (Coordinates, TotalPop))

testData :: [City]
testData = [("New York City", ((1,1), [5, 4, 3, 2])),
           ("Washingotn DC", ((3,3), [3, 2, 1, 1])),
           ("Los Angeles", ((2,2), [7, 7, 7, 5]))]

getPopGrowth :: [City] -> Name -> String
getPopGrowth cs name = concat
    [getPercentages z ++ "\n" | (x,z) <- maybeToList (lookup name cs)] where
    getPercentages z = unwords (map show z1) ++ "% " where
        z1 = percentageIncrease z

percentageIncrease :: [Int] -> [Float]
percentageIncrease (x:xs)
    | length (x:xs) > 2 = percentageIncrease (tail xs)
    | otherwise = (a / b - 1) * 100.0 where
        a = fromIntegral x :: Float
        b = fromIntegral (head xs) :: Float

And the error I'm getting at the moment is:

error:
    • Couldn't match expected type ‘[Float]’ with actual type ‘Float’
    • In the expression: (a / b - 1) * 100.0
      In an equation for ‘percentageIncrease’:
          percentageIncrease (x : xs)
            | length (x : xs) > 2 = percentageIncrease (tail xs)
            | otherwise = (a / b - 1) * 100.0
            where
                a = fromIntegral x :: Float
                b = fromIntegral (head xs) :: Float
   |
92 |     | otherwise = (a / b - 1) * 100.0 where
   |                   ^^^^^^^^^^^^^^^^^^^

I would like to emphasise, I understand the error, but I do not know how to resolve it in such a way that I get the desired outcome of the function. Just for some clarity around what I'm trying to do. Input: getPopGrowth testData "New York City" should Output: 25% 33.333% 50%

Alex
  • 277
  • 1
  • 2
  • 12
  • 1
    You are returning the value of the first two elements only .. you need to keep calculating other values. – Mahmoud S. Marwad May 11 '21 at 12:50
  • 1
    Also to output the string like this "25% 33.333% 50%" you need to use a function like printf to print floats in a custom format. – Mahmoud S. Marwad May 11 '21 at 12:52
  • 1
    have you tried disentangling, narrowing and splitting your functions into smaller and smaller ones trying to isolate and locate your error? – Will Ness May 11 '21 at 17:27

1 Answers1

3

So far, you only calculate the percentage when the list has exactly two elements left. Less elements are not covered, and for longer lists, in all the steps before, the elements get dropped without further action. In the last step, however, you return a single Float instead of a list.

The following example creates an increase percentage in every step, concatenating it with the list resulting from applying the function to the tail of the list. Also, the base cases are all covered:

percentageIncrease :: [Int] -> [Float]
percentageIncrease [] = []
percentageIncrease (x:[]) = []
percentageIncrease (x:y:xs) = ((a / b - 1) * 100.0) : percentageIncrease (y:xs) where
                                a = fromIntegral x :: Float
                                b = fromIntegral y :: Float

Console output:

*Main> getPopGrowth testData "New York City"
"25.0 33.333336 50.0% \n"
jf_
  • 2,199
  • 2
  • 6
  • 23