Reputation: 43
fac n = if n < 2 then 1 else n * fac (n-1)
main = do
putStrLn "Enter a number: "
number <- getLine
print $ number >>= fac
I do not know how to write a recursive factorial function without if statements. Our professor said somethings about lambda calculus.
Upvotes: 3
Views: 4659
Reputation: 16213
try this:
factorial 0 = 1
factorial n = n * factorial (n - 1)
Using tail recursion:
factorial n = f n 1
f 0 acc = acc
f n acc = f (n-1) (acc*n)
main = print $ factorial 5
output:
120
Upvotes: 3
Reputation: 48580
If/then/else and guards are actually just syntactic sugar for pattern matching.
if b
then c
else d
desugars to
case b of
True -> c
False -> d
Similarly,
f x
| b = c
| d = e
f x = g
desugars to
f x = case b of
True -> c
False -> case d of
True -> e
False = g
So you can always use case
directly. However, there's a rather simple optimization you can perform by hand. If you see
case x == p of
True -> a
False -> b
where p
is made of constructors and literals, you can replace the whole thing with
case x of
p -> a
_ -> b
Upvotes: 1
Reputation: 152682
Pattern matching and guards are two particularly straightforward ways. Guards are essentially another syntax for if-then-else; they look like this:
fac n | n < 2 = 1
| otherwise = n * fac (n-1)
Unlike if-then-else, they cleanly support multiple conditions; one could also write, for example,
fac n | n < 0 = error "nah"
| n == 0 = 1
| n == 1 = 1
| n > 1 = n * fac (n-1)
which would look much less pretty in if-then-else form.
With pattern matching, one would typically write multiple defining equations:
fac 0 = 1
fac 1 = 1
fac n = n * fac (n-1)
For numbers in particular, this also desugars to essentially an if-then-else; but for data types with less compiler integration often cannot be emulated with if-then-else, and also often leads to very natural-looking code.
Another very nice approach would be to push your recursion into existing Prelude functions; the more you can spot iteration patterns in practice the more bugs you can avoid by not re-implementing the same loops over and over. For this one, you might use product
and the special enumeration syntax:
fac n = product [1..n]
A more advanced (and significantly worse) technique would be to define a new kind of number; e.g. Church numerals allow the producer of the number to drive the recursion, and the consumer (here, fac
) to just supply base cases. In this style, you might see something like this:
fac n = fst (n (1,1) (\(prod, sum) -> (prod*sum, sum+1)))
(But note well that this requires a very special kind of number -- certainly the type of fac
is not one of a function that could accept Int
or Integer
!) This joke is taken to its logical and horrifying conclusion in The Evolution of a Haskell Programmer.
Upvotes: 7