Search code examples
haskelllambda-calculus

How to write recursive factorial function in haskell without if then else statment


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.


Solution

  • 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.