1

I'm new to Haskell, so I don't quite know how to manipulate the order of operations in a guard or put more constrictions on my 'where' expression in a guard. Here is my first program in Haskell, in which there is some mythical marking scheme that needs to be followed, and it returns you your letter grade. It works perfectly for all non-negative inputs, but the round function seems to fail on negative inputs. Here is my code:

roundMark :: Float -> Integer
roundMark mark
    | mark2 < 0 = 0
    | mark2 > 100 = 100
    | otherwise = mark2
    where mark2 = round mark

letterGrade :: Float -> Char
letterGrade mark 
    | newMark < 48 = 'F'
    | newMark >= 48 && newMark < 65 = 'C'
    | newMark >= 65 && newMark < 79 = 'B'
    | otherwise = 'A'
    where newMark = roundMark mark

For negative inputs, I get the error

No instance for (Num (Float -> Char)) arising from a use of ‘-’
        (maybe you haven't applied a function to enough arguments?)

I'm wondering if there is a way to either put a restriction on my where expression to return 0 for negative inputs before trying to use the round function, or if I can put my guard in a conditional.

DrJessop
  • 462
  • 6
  • 26
  • What do you mean by it fails for negative numbers? – Carcigenicate Jan 13 '18 at 01:49
  • As in I get the error No instance for (Num (Float -> Char)) arising from a use of ‘-’ (maybe you haven't applied a function to enough arguments?) – DrJessop Jan 13 '18 at 01:55
  • 1
    Post the full error in the question. Superficially, I can't see anything that would cause an error like that. – Carcigenicate Jan 13 '18 at 01:57
  • That looks like a compile time error, not a runtime one. It shouldn't only show that for certain input. And where is it pointing? You don't use `-` anywhere in this code. – Carcigenicate Jan 13 '18 at 02:00
  • I tried my function using letterGrade (-1) instead of letterGrade -1. I didn't know that they were different things. Thank you. – DrJessop Jan 13 '18 at 02:01
  • For future reference, be sure to include the code which causes the error in your question. – Code-Apprentice Jan 13 '18 at 03:41

2 Answers2

4
  1. round is "bankers rounding" or "round to even" but you probably (?) want integer truncation such as floor.

  2. What is the purpose of rounding in this case? a negative number is still less than 48 and will still result in an F just like the value 0.

  3. If you want to round all negatives to zero, and not just negative mark2 to zero then just use the right variable:

.

roundMark :: Float -> Integer
roundMark mark
    | mark < 0 = 0      -- See this line, use `mark` vs `mark2`.
    | mark2 > 100 = 100
    | otherwise = mark2
    where mark2 = round mark
Thomas M. DuBuisson
  • 64,245
  • 7
  • 109
  • 166
  • 1. I want round, so I can round to the nearest integer, so that a 47.8 for example results in a 48, which gets turned into a C rather than an F. – DrJessop Jan 13 '18 at 01:59
  • But anyways, thank you for the help. I fixed mine without even needed a where, just to make my life simpler. – DrJessop Jan 13 '18 at 02:02
  • To round in the American sense (up at `.5` and above) then just add one and truncate. – Thomas M. DuBuisson Jan 13 '18 at 02:24
  • We don't round 100 up to 101 in America, @ThomasM.DuBuisson. You probably mean to add 0.5 and then truncate. – amalloy Jan 13 '18 at 02:55
4

The key here is the difference between letterGrade -1 and letterGrade (-1). letterGrade -1 says to take the value of letterGrade and subtract 1. letterGrade (-1) says to apply the function letterGrade to the value -1. This is is because - is an operator in both cases. -1 is not the number "negative one". Rather it is an operator signified by the symbol - and the integer value 1. The problem is that the - operator has two flavors: unary and binary. In order to differentiate between these two uses of -, the creators of Haskell decided to use (-1) to signify the unary operator which takes the "negative" of the given number. Without the parentheses, the - is the binary subtraction operator.

See Why is the unary minus operator problematic in this expression: (- 2) 1? and its linked questions for further discussion on this topic.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • 1
    Most of the time, unary minus is used with parentheses in practice, but more precisely it’s a syntactic form (like `do`, `let`, or lambda) so expressions like `letterGrade $ -1` are also valid. – Jon Purdy Jan 13 '18 at 04:00