0% found this document useful (0 votes)
35 views85 pages

CS1010S-Lec-02 Functional Abstraction

The document discusses functional abstraction in programming by explaining what functions are, how they are defined versus invoked, and why functions are useful for managing complexity, allowing code reuse, and making programs easier to understand and debug. Functions abstract away implementation details and separate specification from implementation.

Uploaded by

Akane Yori
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views85 pages

CS1010S-Lec-02 Functional Abstraction

The document discusses functional abstraction in programming by explaining what functions are, how they are defined versus invoked, and why functions are useful for managing complexity, allowing code reuse, and making programs easier to understand and debug. Functions abstract away implementation details and separate specification from implementation.

Uploaded by

Akane Yori
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 85

CS1010S Programming Methodology

Lecture 2
Functional Abstraction

23 Aug 2023
Admin Matters
• Recitation classes start tomorrow.
• Use of ChatGPT
• Recitations/Tutorials on 1st Sept.
Don’t Stress
Please do your work

Try not to submit at 23:58

DO NOT plagiarize!
Quick Revision!
Variables
•Each variable has:
•Name
•Value
•Address
•Every variable can
hold data of a single
kind at a given time.
Operators
Assignment
a = 5
Equality testing
a == 5
Not equal
a != 5
#Comments
# this is not a hashtag!

>>> print("Good to go")


"Good to go"

#print("Good to go")
# whatever is after the # is ignored
Python Imaging Library

What's this?
from PIL import *
(Mission 0)
CS1010S Road Map
Searching & Sorting
Object-Oriented ADVANCED
Programming

Higher-Order Multiple INTERMEDIATE


List
Procedures Processing Representations

Functional Data BASIC


Iteration Mutation &
Abstraction
Abstraction State
Wishful Recursion
Order of
Thinking Growth

Fundamental concepts of computer programming


Functional Abstraction
What is a function?

Inputs Function Output


Functions aren’t new to us!

𝜃
𝑎
Find x?
𝑎 = 𝑥 cos(𝜃)

function input
Question:
How do we square a
number?
Define Name Input

𝑥 def square(x):
Square
𝑥2

return x * x
Return Output
square(21) 441 def square(x):
return x * x
square(2 + 5) 49

square(square(3)) 81
𝑥 𝑥2 + 𝑦2
𝑦 sum_of_squares

def sum_of_squares(x, y):


return square(x) + square(y)

sum_of_squares(3, 4) 25
𝑎
𝑏 sum_of_squares 𝑐

from math import sqrt


c
a
def hypotenuse(a, b):
return sqrt(sum_of_squares(a, b))
b

hypotenuse(5, 12)

13
Syntax of writing a function!
def <name> (<parameters>):
<body>

Name
- Symbol associated with the function
Parameters (inputs)
- Names used in the body to refer to the arguments of the function
Body
- The statement(s) to be evaluated
- Has to be indented (standard is 4 spaces)
- Can return values as output
Definition versus Invocation
Definition def square(x):
return x * x

def <name> (<parameters>):


<body>

square(5)
Invocation square(6)

<name> (<parameters>)
Definition versus Invocation
def fun(x): return x / 0
Will this raise an error?
fun(2)

The body of the function is NOT executed until it is called!

If the code block consists


of the single line, it can
be written on the same
line after the :
Function – a black box

Inputs Function Output

OutputDon’t
is returned
need towith
know how it statement
return works
Return
Just know
typewhat
can be
it does
None
Functional Abstraction
Managing Complexity
Functional Abstraction

Primitives
Problem Solution
Abstractions
Invented to make
the task easier

What makes a good abstraction?


def multiply(a, b):
ans = 0
count = 1
while count <= b:
ans = ans + a Operators in Python are
already an abstraction for
count = count + 1 the programmer!

return ans

multiply(a, b)
Why functions?

Makes it more natural to think


about tasks and subtasks
House Bricks

Rooms
Divide and
Walls
Conquer
Bricks
Program Primitives

Functions
Divide and
Conquer
Primitives
Why functions?

Makes program easier to


understand
def hypotenuse(a, b):
return sqrt((a*a) + (b*b))

def hypotenuse(a, b):


return sqrt(sum_of_squares(a, b))
def sum_of_squares(x, y):
return square(x) + square(y)
def square(x):
return x * x
Why functions?

Captures common patterns

Examples coming soon!


Why functions?

Allows for code reuse


Another Example
Function to calculate area of circle given the radius

pi = 3.14159
Imagine… If we hadn’t
def circle_area_from_radius(r): had most commonly used
return pi * square(r) operators such as
*, /, //, %!

given the diameter:

def circle_area_from_diameter(d):
return circle_area_from_radius(d/2)
Why functions?

Hides irrelevant details


Ok for some
chemical analyses,
inadequate for
others.
Water molecule
represented as 3 balls

No need to know how a car works to drive it!


variable Function
print value to the output!

Do I really know how print works?


Why functions?
what
Separates specification from
implementation
how
def square(x):
return x * x
Why would we want
to implement a
def square(x): function in different
return exp(double(log(x))) ways?
def square(x): (Lec 4)

return sqrt(x**4)
def square(x):
return x**2
Why functions?

Makes debugging easier


def hypotenuse(a, b):
return sqrt((a + a) * (b + b)) Where is the bug?

def hypotenuse(a, b):


return sqrt(sum_of_squares(a, b))

def sum_of_squares(x, y):


return square(x) + square(y)

def square(x): return x + x


Functional abstraction (Summary)
1. Divides the messy problem into natural subtasks
2. Makes program easier to understand
3. Captures common patterns
4. Allows code reuse
5. Hide irrelevant details
6. Separates specification from implementation
7. Makes debugging easier
Scope of variables
x = 10
def square(x): return x * x
def double(x): return x + x
def addx(y): return y + x

• square(20)
• square(x) Which x ?
• addx(5)
Scope of variables
formal parameter

def square(x):
return x * x body

A function definition binds its formal


parameters.
i.e. the formal parameters are visible only inside
the definition (body), not outside.
Scope of variables
formal parameter

def square(x):
return x * x body

• Formal parameters are bound variables.


• The region where a variable is visible is called
the scope of the variable.
• Any variable that is not bound is free.
Scope of variables
x = 10

def square(x):
return x * x x is bound

def double(x):
x is bound
return x + x

def addx(y): y is bound, x is free


return y + x
Example Global
x = 10
y = 20
x, y = 10, 20 square
double
def square(x): return x * x addx
def double(x): return x + x
def addx(y): return y + x square square
x = 20 x = 10
return = 400 return = 100

square(20)
square(x)
addx
addx(5) y=5
return = 15
Example Global
Global
a=3
a=3
b=4
b=4
a, b = 3, 4 hypotenuse
hypotenuse
c=5
def hypotenuse(a, b):
def sum_of_squares():
return square(a) + square(b)
hypotenuse
return math.sqrt(sum_of_squares()) hypotenuse
a=4
a=4
b=3
b=3
sum_of_squares
sum_of_squares
c = hypotenuse(4, a) return=5
math.sqrt sum_of_squares
return = 5 return = 25
Abstract Environment
Picture Language
(runes.py)
Also graphics.py + image2gif.py
Primitives: show

show(rcross_bb)

show(corner_bb)
Picture object
show(sail_bb)
show(nova_bb)
show(heart_bb)
Primitives are functions!

picture show
Primitives: quarter_turn_right
operation picture
clear_all()
show(quarter_turn_right(sail_bb))

result is
another picture

picture quarter_turn_right picture

show
Derived: turn_upside_down
def turn_upside_down(pic):
return quarter_turn_right(
quarter_turn_right(pic))
clear_all()
show(turn_upside_down(sail_bb))

picture quarter_turn_right picture


turn_upside_down
picture quarter_turn_right
Derived: quarter_turn_left
def quarter_turn_left(pic):
return quarter_turn_right(
quarter_turn_upside_down(pic))

clear_all()
show(quarter_turn_left(sail_bb))
Primitive: stack picture1
stack picture3
picture2
clear_all()
show(stack(rcross_bb, sail_bb))
Derived multiple stacking
clear_all()
picture1 picture3
stack
show(stack(rcross_bb, picture2
stack(rcross_bb, picture5 stack
sail_bb) ) picture4
Derived: beside
def beside(pic1, pic2):
return quarter_turn_left(
stack(quarter_turn_right(pic2),
quarter_turn_right(pic1)))
Derived – a more complex function!
clear_all()
show(
stack(
beside(
quarter_turn_right(rcross_bb),
turn_upside_down(rcross_bb)),
beside(
rcross_bb,
quarter_turn_left(rcross_bb))))

Let's give it a name make_cross


How to write make_cross function?
def make_cross(pic):
stack( return stack(
beside( beside(
quarter_turn_right(rcross_bb), quarter_turn_right(pic),
turn_upside_down(rcross_bb)), turn_upside_down(pic)),
beside( beside(
rcross_bb, pic,
quarter_turn_left(rcross_bb)))) quarter_turn_left(pic))))``
Storing the return values!
my_pic = make_cross(sail_bb)
show(my_pic)

my_pic_2 = make_cross(nova_bb)
show(my_pic_2)
Repeating the pattern
clear_all()
show(make_cross(make_cross(nova_bb)))
Repeating the pattern pat(pat(pat(pat(pic))))
pat(pat(pat(pic)))

def repeat_pattern(n, pat, pic): pat(pat(pic))

if n == 0: pat(pic)

return pic recursion pic

else:
return pat(repeat_pattern(n-1, pat, pic)) repeat_pattern(4)

pat(repeat_pattern(3))
show(repeat_pattern(4, make_cross, nova_bb))
pat(repeat_pattern(2))

pat(repeat_pattern(1))

pat(repeat_pattern(0))
repeat_pattern(0)
clear_all()
show(repeat_pattern(4, make_cross, rcross_bb))
Anonymous(aka lambda) functions
def square(x):
return x * x
input output

foo = lambda x: x * x

function

foo(1) 1
foo(4)
16
New patterns!
anonymous
show(repeat_pattern(3, function
lambda pic: beside(pic, pic),
nova_bb))

clear_all()
show(repeat_pattern(3,
lambda pic: stack(pic, pic),
nova_bb))
Primitive: stack_frac
clear_all()
show(stack_frac(1/3, rcross_bb, sail_bb))
Repeating the pattern
def stackn(n, pic):
if n == 1:
return pic
else:
return stack_frac(1/n,
pic,
stackn(n-1, pic))
clear_all()
show(stackn(3, nova_bb))

clear_all()
show(stackn(5, nova_bb)) Homework!
One final pattern!
clear_all()
show(stackn(5, quarter_turn_right(
stackn(5, quarter_turn_left(nova_bb)))))
No idea how a picture is
rcross_bb
represented! sail_bb

sail_bb heart_bb
Data Abstraction
No idea how the operations
actually do their work
show quarter_turn_right stack

Functional Abstraction
Yet, we can build
complex pictures
repeat_pattern(4, make_cross, rcross_bb)
Functional Abstraction
Wishful Thinking
Pretend you have whatever you need
Another example: Taxi Fare Calculation
NTUC Comfort, the largest taxi operator in Singapore, determines the
taxi fare based on distance traveled as follows:

• For the first kilometre or less: $2.40


• Every 200 metres thereafter or less up to 10 km: $0.10
• Every 150 metres thereafter or less after 10 km: $0.10
Problem:
Write a Python function that
computes the taxi fare from distance
travelled.
How do we start?
Formulate the problem

Function

Needs a name
Pick an appropriate name
(not foo)
Formulate the problem
distance Taxi Fare fare
• What data do • Results should be
you need? unambiguous

• Where would
you get it? • What other abstractions
may be useful?
• Ask the same questions for
each abstraction.
How to compute the result?

1. Try simple examples


2. Strategize step by step
3. Write it down and refine
How to compute the result?

• e.g. #1: distance = 800 m, fare = $2.40


• e.g. #2: distance = 3,300 m
fare = $2.40 + 2300/200 × $0.10
= $3.60
• e.g. #3: distance = 14,500 m
fare = $2.40 + 9000/200 × $0.10 + 4500/150 × $0.10
= $9.90
Solution
• What to call the function? taxi_fare

• What data are required? distance

• Where to get the data? function argument

• What is the result? fare


Pseudocode
Case 1: distance <= 1000
fare = $2.40

Case 2: 1000 < distance <= 10,000


fare = $2.40 + $0.10 * (distance – 1000)/200

Case 3: distance > 10,000


fare = $6.90 + $0.10 * (distance – 10,000)/150)

Note: the Python function ceil rounds up its argument.


math.ceil(1.5) = 2
Program
def taxi_fare(distance): # distance in metres
if distance <= 1000:
return 2.4
elif distance <= 10000:
return 2.4 + (0.10 * ceil((distance – 1000) / 200))
else:
return 6.9 + (0.10 * ceil((distance – 10000) / 150))

# check: taxi_fare(3300) = 3.6

•Can we improve this solution?


Generalisability?
What if…
1. the starting fare increases?
2. Stage distance changes?
3. Increment amount changes?
Avoid magic numbers!

It is a terrible idea to hardcode numbers (magic


numbers):
• Hard to make changes in future

Define abstractions to hide them!


def taxi_fare(distance): # distance in metres
if distance <= stage1:
return start_fare
elif distance <= stage2:
return start_fare +
(increment * ceil((distance - stage1) / block1))
else:
return taxi_fare(stage2) +
(increment * ceil((distance - stage2) / block2))
stage1 = 1000
stage2 = 10000
start_fare = 3.2
increment = 0.22
block1 = 400
block2 = 350
Summary Why functions are good!
• Functional Abstraction 1. Divides the messy problem into natural
• Good Abstractions subtasks
• Variable Scoping 2. Makes program easier to understand
• Wishful Thinking 3. Captures common patterns
4. Allows code reuse
5. Hide irrelevant details
6. Separates specification from
implementation
7. Makes debugging easier

You might also like