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 False
True
False
Indentation 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 y
f x y
Conventional infix form for convenience (syntactic sugar)
add x y
written x + y
Function 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
True
Function 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 help
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.
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
-4249290049419214848
Apply 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 overflow
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
Apply function fact5
to -1 – returns value
*Fact> fact5 (-1)
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
Quit GHCi (:q
)
:quit
Leaving GHCi.
To edit source from within GHCi (using e.g., Aquamacs)
EDITOR
export EDITOR=Aquamacs
:set editor Aquamacs
:edit
command invokes editor