CSci 450/503: Programming Languages

Our First Haskell Functions

H. Conrad Cunningham

30 August 2017

Acknowledgements: These slides accompany section 2.2, “Defining Our First Haskell Functions” of Chapter 2 “Basic Haskell Functional Programming” of “Introduction to Functional Programming Using Haskell”.

Advisory: The HTML version of this document may require use of a browser that supports the display of MathML. A good choice as of August 2017 is a recent version of Firefox from Mozilla.

Code: The factorial functions in this set of slides are collected into Haskell module Fact.hs. The source file TestFact.hs gives a simple test script.

Defining Our First Haskell Functions

Mathematical Factorial Definitions

  1. Using product operator:

    • fact(n)=i=1i=ni(n) = \prod_{i=1}^{i=n}\,i
      • fact(4)=1×2×3×4(4) = 1 \times 2 \times 3 \times 4.
      • fact(0)=1(0) = 1identity element for multiplication
  2. Using recursive definition (or recurrence relation):

    • fact’(n)=1(n) = 1, if n=0n = 0
      fact’(n)=n×(n) = n \times fact’(n1)(n-1), if n1n \geq 1
      • base case: n=0n = 0
      • recursive: fact(n)(n) defined in terms of fact’(n1)(n-1)
      • terminates, gets closer to 0 on each step

Factorial Using if-then-else (1)

    fact1 :: Int -> Int 
    fact1 n = if n == 0 then 
                  1 
              else 
                  n * fact1 (n-1) 

Factorial Using if-then-else (2)

    fact1 :: Int -> Int 
    fact1 n = if n == 0 then 
                  1 
              else 
                  n * fact1 (n-1) 

Factorial Using if-then-else (3)

    fact1 :: Int -> Int 
    fact1 n = if n == 0 then 
                  1 
              else 
                  n * fact1 (n-1) 

Factorial Using if-then-else (4)

    fact1 :: Int -> Int 
    fact1 n = if n == 0 then 
                  1 
              else 
                  n * fact1 (n-1) 

Function Application

Factorial Using Guards

    fact2 :: Int -> Int 
    fact2 n 
      | n == 0    = 1 
      | otherwise = n * fact2 (n-1)

Factorial Using Pattern Matching

    fact3 :: Int -> Int 
    fact3 0 = 1 
    fact3 n = n * fact3 (n-1)

Factorial Using Partial Function (1)

    fact4 :: Int -> Int 
    fact4 n 
        | n == 0 =  1 
        | n >= 1 =  n * fact4 (n-1)

Factorial Using Partial Function (2)

    fact4' :: Int -> Int 
    fact4' n 
      | n == 0    =  1 
      | n >= 1    =  n * fact4' (n-1)
      | otherwise = error "fact4' called with negative argument"

Factorial Using Library Function

    fact5 :: Int -> Int
    fact5 n = product [1..n]

Implementation Comparison

Code

The factorial functions in this set of slides are collected into Haskell module Fact.hs. The source file TestFact.hs gives a simple test script.

Using GHCi for Factorials (1)

See the Glasgow Haskell Compiler Users Guide

  1. Start the REPL.

    bash-3.2$ ghci
    GHCi, version 8.2.1: http://www.haskell.org/ghc/  :? for help
  2. Load module Fact (file Fact.hs) to get factorial functions – (:l)

    Prelude> :load Fact
    [1 of 1] Compiling Fact             ( Fact.hs, interpreted )
    Ok, 1 module loaded.

Using GHCi for Factorials (2)

  1. Inquire type of fact1

    *Fact> :type fact1 fact1 :: Int -> Int

- `:type` abbreviated `:t`
  1. Apply function fact1

    *Fact> fact1 7
    5040
    *Fact> fact1 0
    1
    *Fact> fact1 20
    2432902008176640000
    *Fact> fact1 21
    -4249290049419214848

Using GHCi for Factorials (3)

  1. Apply functions fact2, fact3, fact4, fact5

    *Fact> fact2 7
    5040
    *Fact> fact3 7
    5040
    *Fact> fact4 7
    5040
    *Fact> fact5 7 
    5040 
  2. Apply first 3 functions to -1 – slow death

    *Fact> fact1 (-1)
    *** Exception: stack overflow
    *Fact> fact2 (-1)
    *** Exception: stack overflow
    *Fact> fact3 (-1)
    *** Exception: stack overflow

Using GHCi for Factorials (4)

  1. Apply function fact4 to -1 – quick death

    *Fact> fact4 (-1)
    *** Exception: Fact.hs:(33,1)-(35,29): Non-exhaustive patterns 
        in function fact4
    Fact> fact4' (-1)
    *** Exception: fact4' called with negative argument
    CallStack (from HasCallStack):
      error, called at Fact.hs:50:17 in main:Fact
  2. Apply function fact5 to -1 – returns value

    *Fact> fact5 (-1)
    1

Using GHCi for Factorials (5)

  1. Set +s option for e time/space – +t option for return type

    *Fact> :set +s
    *Fact> fact1 20
    2432902008176640000
    (0.00 secs, 80,672 bytes)
    *Fact> :set +t
    *Fact> fact1 20
    2432902008176640000
    it :: Int
    (0.00 secs, 80,720 bytes)
    *Fact> :unset +s +t
    *Fact> fact1 20
    2432902008176640000

Using GHCi for Factorials (6)

  1. Quit GHCi (:q)

    :quit
    Leaving GHCi.