Search code examples
haskellrecursionpartial-application

No instance for (Num (Int -> Int)) arising from a use of syntactic negation


I have written the following Haskell code to return the primary and secondary diagonal of [[Int]]

getDiagonal' :: [[Int]] -> Int -> (Int -> Int) -> [Int]
getDiagonal' [] _ _ = []
getDiagonal' (x:xs) i fn = i' : getDiagonal' xs (fn i) fn
  where i' = head $ drop i x

getPrimaryDiagonal :: [[Int]] -> [Int]
getPrimaryDiagonal x = getDiagonal' x 0 (+1)

getSecondaryDiagonal :: [[Int]] -> [Int]
getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (+(-1))

However, I would have thought that the final line could be the following, using (-) the same way as (+)

getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (-1)

However, that does not work, when I do that I get

Main.hs:27:59: error:
    • No instance for (Num (Int -> Int))
        arising from a use of syntactic negation
        (maybe you haven't applied a function to enough arguments?)
    • In the third argument of ‘getDiagonal'’, namely ‘(- 1)’
      In the expression: getDiagonal' x ((length x) - 1) (- 1)
      In an equation for ‘getSecondaryDiagonal’:
          getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (- 1)

Why does (-) produce that error?


Solution

  • (-1) is interpreted as negative one, it is, as far as I know, the only exception that is made for operators that are non-binary. (-1) is thus not a function that subtracts one away.

    You can make use of subtract :: Num a => a -> a -> a for this:

    getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (subtract 1)

    or you can use flip :: (a -> b -> c) -> b -> a -> c which is how subtract is implemented:

    getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (flip (-) 1)