Title: An Introduction to
1An Introduction to Functional Programming
Jon Allen
http//perl.jonallen.info - jj_at_jonallen.info
2Programming Styles
- The Perl language supports multiple programming
styles, providing many different options for
program structure and code reuse - Procedural
- Sequence of statements
- Subroutines
- Object Oriented
- Objects, properties, methods
- Classes, inheritance
3Functional Programming
- Functional programming involves creating and
manipulating functions to build up larger
programs. - e.g. converting rand() into dice()
- This requires a language that allows functions to
be used as input and return data to other
functions. - Perl has two important features that make this
possible - Code references
- Closures
4References
- A reference is a pointer to data
- References are scalar variables - reference
- Used to create complex data structures
- See http//perldoc.perl.org/perlreftut.html
my hash ( one gt Hello, two gt World
) my hashref \hash my arrayref
1,2,3,5,99 print hashref
prints HASH(0x800368) print hashref-gtone
prints Hello print hashreftwo
prints World
5Code References
- A code reference is a pointer to code
sub hello print Hello, World! my
helloref \hello my goodbye sub my
name shift print Goodbye,
name! helloref-gt() Prints
Hello, World! helloref
Prints Hello, World! goodbye-gt(JJ)
Prints Goodbye, JJ! goodbye(JJ)
Prints Goodbye, JJ!
6Closures
- A closure is when a code reference is created
which refers to variables outside its lexical
scope
sub make_dice my sides shift return sub
return int(rand sides) 1
When the subroutine finishes, the
sides variable goes out of scope my d6
make_dice(6) my d10 make_dice(10) print
d6-gt() Rolls the dice print
d10-gt()
7Functions as Data
- By using code references as data, functions can
manipulate other functions
sub combine my (modifier,input) _at__
return sub return modifier-gt(input-gt(_at__))
my hello sub return Hello,
.shift print hello-gt(JJ)
Prints Hello, JJ! my upper sub return uc
shift my HELLO combine(upper,hello) print
HELLO-gt(World) Prints HELLO,
WORLD!
8Practical Applications
- Functional programming techniques have many
real-world uses - Separate control flow (business logic) from
implementation - Create common function libraries to support code
reuse - Simplify complex algorithms
- Key enabler for list processing parallel
execution - map - process each element of a list
- reduce - combines list elements to a single value
- See http//www.joelonsoftware.com/items/2006/08/01
.html
9Iterators
- An iterator returns the next value in a sequence
each time it is called. - Filehandles are iterators - ltDATAgt returns the
next line (or undef). - Iterator for an array
sub list_iterator my _at_items _at__ return
sub return shift _at_items
10Iterators (2)
- By turning an list into a function, we can
process the list elements by manipulating the
function
my _at_numbers qw/one two three four/ my
number_iterator list_iterator(_at_numbers) my
upper sub return uc shift my
uc_numbers combine(upper,number_iterator
) while (my number uc_numbers-gt())
print number\n Prints the
following ONE TWO THREE FOUR
11Ordered Best Fit
- Problem Given an ordered list of files, burn
them onto potentially multiple CD-ROMs. - Generic problem - Fitting things into other
things - Applications in
- Word-wrap
- Page layout / HTML rendering
- Logistics (loading vans / boxes etc)
- Trapping overflow conditions
12Using a foreach() loop
- With foreach(), we only know the limit has been
breached after the event
my _at_filenames get_file_list() Initial
list my _at_cd_list ()
Temporary storage foreach my file (_at_filenames)
push _at_cd_list,file if (sizeof(_at_cd_list) gt
max_size) burn_cd(splice(_at_cd_list,0,-1))
if (_at_cd_list) burn_cd(_at_cd_list)
13Using an indexed loop
- With an indexed loop, we need to look ahead to
see if the limit will be breached on the next
loop
my _at_filenames get_file_list() Initial
list my _at_cd_list ()
Temporary storage foreach my file_id (0 ..
_at_filenames) if (sizeof(_at_cd_list,filenamesf
ile_id1) gt max_size) burn_cd(splice
_at_cd_list) push _at_cd_list,filenamesfile_id
if (_at_cd_list) burn_cd(_at_cd_list)
14Aggregators
- An aggregator combines an iterator and a limit
function, creating a new iterator that returns
groups
sub aggregator my (iterator,limit_function)
_at__ my _at_buffer return sub while(1)
my value iterator-gt() or return
splice _at_buffer push _at_buffer,value
if (limit_function-gt(_at_buffer)) return
splice(_at_buffer,0,-1)
15Using an Aggregator
- With an aggregator function, the control flow is
much simpler - note that we only have a single
line of code which calls burn_cd()
my file_iterator make_iterator(get_file_list())
my limit sub sizeof(_at__) gt
max_size my iso_list
aggregator(file_iterator,limit) while (my
_at_cd_list iso_list-gt()) burn_cd(_at_cd_list)
16Building a calendar
- Problem Display a calendar for a given month in
the following format - Taken from the Microsoft Scripting Games 2008
April 2008 Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30
17Can you count?
- Given a start date, create an iterator which
returns each subsequent date
use TimePiece use TimeSeconds Core with
Perl 5.10 my first_day TimePiece-gtstrptime("
year-month-01",
"Y-m-d") my every_day
day_iterator(first_day) sub day_iterator
my day shift return sub my today
day day ONE_DAY return today
18Can you stop counting please?
- We only want to iterate through dates while they
are still within the specified month
my days_in_month iterate_while(every_day, sub
_-gtmon month and
_-gtyear year ) sub
iterate_while my (iterator,condition)
_at__ return sub local _ while
(defined (_ iterator-gt())) return
(condition-gt()) ? _ undef
19But we want weeks, not days
- One week of dates in an array (_at_w)
- w21 (Tuesday 1st April), w32 (Wednesday
2nd April) - Missing days are undef (e.g. w1 would have
been 31st March) - Next week, w06 (Sunday 6th), w612
(Saturday 12th) etc.
sub cal_week_function my next_day shift
my _at_week return sub while (1) my
day next_day-gt() or return splice _at_week
_at_weekday-gtday_of_week day-gtday_of_month
return splice _at_week if (_at_week 7)
20Calendar - done!
- With a function to return complete weeks,
printing the calendar is easy - Very simple to change the output format
- For example, render the calendar in HTML
my calendar_week cal_week_function(days_in_mon
th) say first_day-gtfullmonth," year\n" say
join ' ',TimePieceday_list while (my _at_week
calendar_week-gt()) say join ' ',map
sprintf("3s", _ // '') _at_week
21Conclusions
- Functional programming techniques can be very
useful in improving the maintainability of your
code. - Not suitable for every problem - procedural and
object-oriented programming still have their
place. - Perl lets you use all three styles in the same
program. - Further reading
- Higher Order Perl by Mark Jason Dominus
- http//perl.plover.com/hop
22Fin!
Thank you for listening!
Any questions? http//perl.jonallen.info/talks