Title: Functional Programming
1Functional Programming
- Here we briefly look at what functional
programming is and why we want to study it - a function, in the mathematical sense, is a set
of operations that perform some computation on
the parameter(s) passed, and return a value - a function, in a programming language, is a set
of code whose purpose is to compute based on the
parameter(s) and return a value - Functions are often used to promote modularity
- break down program tasks into small, roughly
independent pieces - this promotes structured programming in terms of
design - this also aids debugging, coding and maintenance
- However, the function, as we see them in
programming languages, does not necessarily
reflect a mathematical function
2Why Not?
- Functions may act more like procedures
- a procedure is another unit of modularity
- the idea behind a procedure is to accomplish one
or more related activities - the activities should make up some logical goal
of the program but may not necessarily be based
on producing a single result - procedures may return 0 items or multiple items
unlike functions - In languages like C, there are no procedures, so
functions must take on multiple roles - mathematical types of functions
- functions that act as procedures
- Such functions can produce side effects
- mathematical functions do not produce side effects
3Functional Design
- Functions should
- be concise
- accomplish only a single task or goal
- return one item
- in CL, if we need to return multiple values, we
can wrap them into a list (or other structure) - there is also a way to have CL functions return
multiple values although that is generally
discouraged - have no side effects
- because the assignment operations are done by
function calls, the function calls must produce
side effects in such circumstances, but in
general, YOUR code should not produce side
effects - destructive operations are available and are
often much more efficient than their
non-destructive counterparts, but should not be
used haphazardly or just because they are more
efficient - use parameter passing for communication
- rather than global variables
- exploit recursion when possible
- this simplifies the body of a function and
requires fewer or no local variables
4Comparison Example
(defun bad-reverse (lis) (let ((size
(length lis)) (limit (truncate (/ size 2)))
temp) (dotimes (i limit) (setf
temp (nth i lis)) (setf (nth i lis) (nth (-
size i 1) lis)) (setf (nth (- size i 1) lis)
temp)) lis)) (defun better-reverse
(lis) (let ((temp nil) (size (length
lis))) (dotimes (i size) (setf temp
(append temp (list (nth (- size i 1) lis)))))
temp)) (defun best-reverse (lis) (if
(null lis) nil (cons (car (last lis))
(best-reverse (butlast lis)))))
The most efficient version but also destructive
Non-destructive, less efficient because of the
loop and use of temp
Recursive with no local variables
5CL Functions/Operations to be Avoided
The following are all destructive with side
effects We might wish to minimize their usage
- set
- setq
- setf
- psetf
- psetq
- incf
- decf
- push
- pop
- pushnew
- rplaca
- rplacd
- rotatef
- shiftf
- remf
- remprop
- remhash
Obviously, we will need to use some of these,
perhaps often (such as setf) We can avoid using
these if we implemented functions with recursion
instead of iteration, but that will not
usually be practical (most of us are not good at
recursion)
Note that this does not include the n-destructive
functions like nconc and nreverse since there
are non-destructive counterparts, these should be
avoided
6Advantages? of Functional Programming
- Easier to design
- everything is a concise module
- Easier to debug
- if all functions are concise, they contain little
code leading to easier debugging and less need to
insert break statements to find where things are
going wrong - Can lead to more efficient programs
- debatable
- Can lead to more efficient use of the
programmers time - but if you arent good at recursion, is this
going to be true? - Leads to aesthetically cleaner code
- yet can be more awkward to maintain
- Functional languages are often interpreted
- this allows quick implementation and testing
- this allows for incremental design and
implementation of code