Search code examples
haskellquadratic

Haskell Quadratic solution finder - Error


I am using Haskell in college and one of the exercises I have to do is make a function that gives me the roots of a quadratic equation when I give it its coefficients, using a previous function that tells me how many solutions it has. Here's what I have done:

First function, this one works fine:

nRoots :: Float -> Float -> Float -> Int
nRoots a b c | r<0 = 0
             | r==0 = 1
             | otherwise = 2
             where r = b^2-4*a*c

Second function, it does not work:

roots :: Float -> Float -> Float -> [Float]
roots a b c | nRoots==2 = [(-b-sqrt(b^2-4*a*c))/(2*a),(-b+sqrt(b^2-4*a*c))/(2*a)]
            | nRoots==1 = [-b/(2*a)] 
            | otherwise = []

Here's the error I get:

raizes.hs:8:21:
    No instance for (Eq (Float -> Float -> Float -> Int))
      (maybe you haven't applied enough arguments to a function?)
      arising from a use of ‘==’
    In the expression: nRoots == 2
    In a stmt of a pattern guard for
                   an equation for ‘roots’:
      nRoots == 2
    In an equation for ‘roots’:
        roots a b c
          | nRoots == 2
          = [(- b - sqrt (b ^ 2 - 4 * a * c)) / (2 * a),
             (- b + sqrt (b ^ 2 - 4 * a * c)) / (2 * a)]
          | nRoots == 1 = [- b / (2 * a)]
          | otherwise = []

raizes.hs:8:23:
    No instance for (Num (Float -> Float -> Float -> Int))
      (maybe you haven't applied enough arguments to a function?)
      arising from the literal ‘2’
    In the second argument of ‘(==)’, namely ‘2’
    In the expression: nRoots == 2
    In a stmt of a pattern guard for
                   an equation for ‘roots’:
      nRoots == 2

Any idea as to what is going on??

Thanks in advance

EDIT: Thanks for all the answers! I feel quite dumb now for not noticing it :X


Solution

  • You need to provide the appropriate arguments to nRoots, specifically roots a b c | nRoots a b c == 2 = ....

    Your error message tells you that though, so let's go through how you should read this error message from GHC to figure out how this was your problem. I've marked the error message below with several section marks.

    raizes.hs:8:21:
        ---------------------BEGIN SECTION A--------------------
        No instance for (Eq (Float -> Float -> Float -> Int))
          (maybe you haven't applied enough arguments to a function?)
          arising from a use of ‘==’
        In the expression: nRoots == 2
        ---------------------END SECTION A--------------------
        ---------------------BEGIN SECTION B--------------------
        In a stmt of a pattern guard for
                       an equation for ‘roots’:
          nRoots == 2
        In an equation for ‘roots’:
            roots a b c
              | nRoots == 2
              = [(- b - sqrt (b ^ 2 - 4 * a * c)) / (2 * a),
                 (- b + sqrt (b ^ 2 - 4 * a * c)) / (2 * a)]
              | nRoots == 1 = [- b / (2 * a)]
              | otherwise = []
        ---------------------END SECTION B--------------------
    
    raizes.hs:8:23:
        ---------------------BEGIN SECTION C--------------------
        No instance for (Num (Float -> Float -> Float -> Int))
          (maybe you haven't applied enough arguments to a function?)
          arising from the literal ‘2’
        In the second argument of ‘(==)’, namely ‘2’
        In the expression: nRoots == 2
        In a stmt of a pattern guard for
                       an equation for ‘roots’:
          nRoots == 2
       ---------------------END SECTION C--------------------
    

    First let's review the type of ==.

    (==) :: Eq a => a -> a -> Bool
    

    SECTION A tells you that == requires instances of the equality type class (Eq) in order to work because it's overloaded to work for any type which has an Eq instance. Unfortunately there is no (and can be no non-trivial) instance for Eq for nRoots because nRoots itself is a function (think halting problem). The hint that GHC gives here is exactly your problem, namely GHC notices you're trying to compare equality of a function (to a number in this case) and suggests maybe you haven't applied enough arguments to a function?

    Okay so just after SECTION A we already seem to know the problem you're facing, but let's not be too hasty here, maybe it's the case SECTION B and SECTION C will show that the error you're seeing in SECTION A is just a superificial error caused by something deeper.

    Well SECTION B is really just telling you the exactly location of the problem in SECTION A so that's not anything new.

    What about SECTION C? Well remember the type of ==? It turns out that == expects both sides of the equality to be of the same type. So now GHC sees nRoots == 2 and expects both nRoots and 2 to be of the same type. Well numeric literals in Haskell are overloaded to be of type Num a => a so that they can simultaneously represent Ints, Integers, Doubles, Rationals, etc. So now GHC expects nRoots to be of type Num a => a where a in particular must be Float -> Float -> Float -> Int, i.e. it expects nRoots to be an instance of the Num typeclass.

    Well as GHC astutely hints at, this is really just another symptom of the same problem! Namely that you forgot to actually apply arguments to nRoots and so GHC is trying to deal with a bare function rather than the output of the function.

    So Section A and Section C are both telling you that you have the same problem, namely you're trying to use a function itself nRoots when you should be fully applying your arguments to that function and be using the output of that function.