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.
Using product operator:
Using recursive definition (or recurrence relation):
fact1 :: Int -> Int
fact1 n = if n == 0 then
1
else
n * fact1 (n-1)
First line type signature of form object :: type.
Type name begins with uppercase letter
Type fact1 is function (->)
Int) argument, returns integerNo builtin natural number type
fact1 :: Int -> Int
fact1 n = if n == 0 then
1
else
n * fact1 (n-1)
Second line defining equation fname parms = body
') fact1 :: Int -> Int
fact1 n = if n == 0 then
1
else
n * fact1 (n-1)
Body expression if condition then expression1 else expression2
Bool) value, either True or FalseTrueFalseIndentation is significant, indicates nesting
fact1 :: Int -> Int
fact1 n = if n == 0 then
1
else
n * fact1 (n-1)
then clause base case n == 0
else clause recursive case
fact1 to entire expression (n-1) – parenthesisDifference with mathematical definition?
Function application by listing argument expressions after function name
f to argument expressions x and yf x yConventional infix form for convenience (syntactic sugar)
add x y written x + yFunction application higher precedence than others
f x + y same as (f x) + y. fact2 :: Int -> Int
fact2 n
| n == 0 = 1
| otherwise = n * fact2 (n-1)
| denotes guarded equation
TrueFunction fact2 equivalent to fact1
fact3 :: Int -> Int
fact3 0 = 1
fact3 n = n * fact3 (n-1)
Two equations, each with a different pattern in parameter list
0 in first leg matches value 0n in second matches anythingFunctions fact1, fact2, and fact3 equivalent
fact4 :: Int -> Int
fact4 n
| n == 0 = 1
| n >= 1 = n * fact4 (n-1)
To stop “infinite loop”, remove negative integers from domain
Function fact4 undefined for negatives. fails quickly
fact4' :: Int -> Int
fact4' n
| n == 0 = 1
| n >= 1 = n * fact4' (n-1)
| otherwise = error "fact4' called with negative argument"
Function fact4'
fact5 :: Int -> Int
fact5 n = product [1..n]
[1..n] generates list of integers from 1 to n, inclusive
Library function product multiplies elements of list
What if apply fact5 to negative?
[1..0] generates empty listproduct of empty list is 0 – identity for multiplicationfact5 (-1) yields 0The factorial functions in this set of slides are collected into Haskell module Fact.hs. The source file TestFact.hs gives a simple test script.
See the Glasgow Haskell Compiler Users Guide
Start the REPL.
bash-3.2$ ghci
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for helpLoad 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.Inquire type of fact1
*Fact> :type fact1 fact1 :: Int -> Int
- `:type` abbreviated `:t`
Apply function fact1
*Fact> fact1 7
5040
*Fact> fact1 0
1
*Fact> fact1 20
2432902008176640000
*Fact> fact1 21
-4249290049419214848Apply functions fact2, fact3, fact4, fact5
*Fact> fact2 7
5040
*Fact> fact3 7
5040
*Fact> fact4 7
5040
*Fact> fact5 7
5040 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 overflowApply 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:FactApply function fact5 to -1 – returns value
*Fact> fact5 (-1)
1Set +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
2432902008176640000Quit GHCi (:q)
:quit
Leaving GHCi.To edit source from within GHCi (using e.g., Aquamacs)
EDITORexport EDITOR=Aquamacs:set editor Aquamacs:edit command invokes editor