Reputation: 33638
I am trying to learn Haskell, and I defined the following simple recursive function to calculate the factorial.
fact n | n < 0 = error "fact only valid for non-negative integers"
| n == 0 = 1
| n > 0 = n * fact(n-1)
It works fine for a positive integer, and as expected when invoked with a negative integer, it throws the error that I have specified.
What is the problem?: It gives me the same error ("fact only valid for non-negative integers") when I try to apply it to a Fractional, such as fact 10.5
. Why does it give me that same error that I have clearly specified should apply for only the case of n < 0.
Upvotes: 0
Views: 171
Reputation: 80765
If you give it 10.5 as argument, then the third case is valid, and the function calls itself recursively with n = 10.5 - 1 = 9.5
.
That input also triggers the third case, making a recursive call with n = 8.5
.
And so on: 7.5, then 6.5, then 5.5, 4.5, 3.5, 2.5, 1.5, 0.5
And then, on the next iteration, n = -0.5
, which triggers the first case and produces the error. Everything exactly as coded.
If you want your function to work for fractional numbers, you have to (a) define what is a factorial of n
for 0 < n < 1
, and then (b) encode that case.
For example, if I were to define factorial of a number between zero and one to be equal to one, then the function would look like this:
fact n | n < 0 = error "fact only valid for non-negative integers"
| n >= 0 && n <= 1 = 1
| n > 0 = n * fact(n-1)
Also, a side note: I think the above code should give you a warning that the function is partial. This is because the compiler cannot prove that one of the cases should always hold (and in all fairness, depending on the argument type and the definition of Num
and Ord
for it, it might not hold). To avoid this, one should use an otherwise
clause:
fact n | n < 0 = error "fact only valid for non-negative integers"
| n >= 0 && n <= 1 = 1
| otherwise = n * fact(n-1)
Upvotes: 5