Kurt Nørmark
Department of Computer Science, Aalborg University, Denmark
Abstract Previous lecture Next lecture Index References Contents | In this lecture we continue the introduction to functional programming in Scheme. We start with name binding issues, and proceed with conditional expressions, and recursion and iteration. |
Name binding constructs |
The let name binding expression Slide Annotated slide Contents Index References Textbook |
The concept name binding expression: A name binding expression establishes a number of local name bindings in order to ease the evaluation of a body expression | In a name binding construct a number of names are bound to values. The name bindings can be used in the body, which must be an expression when we are working in the functional paradigm. There are a number of variations in the way the names can refer to each other mutually. We will meet some of them on the following pages. |
Syntax: The names n 1 ... n k are bound to the respective values e 1 ... e k , and the body expression is evaluated relative to these name bindings. Free names in the body expression are bound to names defined in the surround of the let construct. |
|
|
|
The equivalent meaning of let Slide Annotated slide Contents Index References Textbook |
|
Syntax: |
|
Syntax: |
|
Examples with let name binding Slide Annotated slide Contents Index References Textbook |
Table. Examples of namebindings with let. The first example shows that all constituents of a function call can be bound to local names - in the example both the function object referred to by a, and two string parameters. The second example illustrates that alternative names, aliases, can be defined for a couple of functions. Notice in particular that g is bound to b (the bold face function), not em (the emphasis function). This can also be seen in the second column. The third example is a little more advanced, and it can first be understood fully on the ground of the material in the lecture about higher-order functions. We bind the name phrase-elements to a list of ten functions. Via mapping, we apply each function to foo, and we present the results in an ul list. |
|
The let* name binding construct Slide Annotated slide Contents Index References Textbook |
|
Syntax: |
|
|
An example with let* Slide Annotated slide Contents Index References Textbook |
Program: A typical example using sequential name binding. The task is to calculate the number of days, hours, minutes, and seconds given
a number of seconds. We subsequently calculate a number of quotients and rest.
While doing so we find the desired results. In this example we would not be able to
use let; let* is essential because a given calculation depends on previous name bindings.
The full example, including the definition of the constants, can be found in the
accompanying elucidative program. The function is part of the LAML time library in lib/time.scm of
the LAML distribution. The time library is used whenever we need to display
time information, such as 'the time of generation' of some HTML files. |
|
A set of functions for handling of time. The set of functions elucidated here is only a subset of the LAML time library. |
|
|
The letrec namebinding construct Slide Annotated slide Contents Index References Textbook |
|
Syntax: |
|
Program: An schematic example of a typical application of letrec for local definition of two mutually recursive functions. |
|
|
LAML time functions Slide Annotated slide Contents Index References Textbook | The function how-many-days-hours-minutes-seconds is part of the LAML time library, which we here illustrate by means of a number of examples. |
Table. Example use of some of the LAML time library functions |
|
Conditional expressions |
Conditional expressions Slide Annotated slide Contents Index References Textbook |
Control structures belong to the imperative paradigm. In the functional paradigm, if and cond are used in conditional expressions. By that we mean expressions, of which subexpressions are selected for evaluation based on one or or more boolean selectors. |
Syntax: |
|
Syntax: |
|
|
Exercise 3.2. HTML Header functions | This is a small exercise that aims at construction of slightly different header functions than those provided by
the native header functions h1, ..., h6. Define a function (header level) which takes a parameter level. The header function should return the similar basic header function provided that n is between one and six. If n is outside this interval, we want header to return the identity function of one parameter. It means that ((header 3) "Header text") is equal to (h3 "Header text") and that ((h 0) "Header text") is just "Header text". Hint: Arrange the header functions in a list, and let header select the appropriate header function from this list. Define a variant of header which returns a native header function if it receives a single parameter (level), and which returns the value, such as, ((header 3) "Header text"), if it receives both a level parameter and a header text string. |
|
Examples with if Slide Annotated slide Contents Index References Textbook |
Table. Examples using an if conditional expression on a Wednesday. In both examples we extract the weekday (a string) from the current time. If it is a Wednesday we emit a paragraph which serves as a reminder of a meeting the following day. If not executed on a Wednesday, we do not want any special text. We achieve this by returning the empty list, which is spliced into the the body context (in the first example) and into the paragraph context (in the second example). The splicing is a result of the handling of lists by the HTML mirror functions in LAML. The two examples differ slightly. In the first example the if is placed on the outer level, feeding information to body. In the second row, the if is placed at an inner level, feeding information to the p function. The two examples also give slightly different results. Can you characterize the results? |
|
|
Example with cond: leap-year? Slide Annotated slide Contents Index References Textbook |
Program: The function leap-year?. The function returns whether a year y is a leap year.
For clarity we have programmed the function with a conditional. In this case,
we can express the leap year condition as a simple boolean expression using and and or. We refer to this
variation below, and we leave it to you to decide which version you prefer. |
|
Program: The function leap year programmed without a conditional. To ease comparison, the original version is shown below the new version. |
|
A complete program for handling of time |
|
Example with cond: american-time Slide Annotated slide Contents Index References Textbook |
Program: The function american-time. The function returns a string displaying the 'am/pm/noon' time given hour h, minute m, and seconds s. |
|
Program: The function american-time with helping functions. |
|
Example with cond: as-string Slide Annotated slide Contents Index References Textbook |
Program: The function as-string converts a variety of Scheme data types to a string. This function makes use of the fact that any kind of data can be passed to the function, without
intervening static type check. At run time we dispatch on the type of x.
The function string-merge is discussed later in this section, cf. the reference from this page. The function as-string, and its sibling functions as-number, as-char, as-symbol, and as-list are used heavily in all LAML software. The functions are convenient because they do not
need to know the type of the input data. In functional languages with static type checking,
we cannot program these functions as shown above. In these language we could overload
the function name as-string, and underneath define a number of individual functions each
taking a particular type of input. |
|
|
Recursion and iteration |
Recursion Slide Annotated slide Contents Index References Textbook |
|
The concept recursion: Recursion is an algorithmic program solving idea that involves solution of subproblems of the same nature as the overall problem |
The problem solving technique sketched here is called divide and conquer. It is not all divide and conquer problems that involve recursion. But many do in fact. Recursion comes into play when the subproblems P1 ... Pn turn out to be of the same nature as the overall problem, and as such they can be solved by the same 'medicine' as used for the overall problem P. |
|
List processing Slide Annotated slide Contents Index References Textbook |
|
Program: A function for extraction of the href attribute from a property list. |
|
Program: An example with property lists that represent HTML attributes in LAML.
As the last interaction, we see the function find-href-attribute in play. |
|
|
Tree processing (1) Slide Annotated slide Contents Index References Textbook |
|
Program: A sample web document with a number of links. The link forms - represented by a elements - are highlighted. |
|
Program: The abstract syntax tree represented as nested lists.
It is hard to read and understand this representation of the tree structure.
It is not really oriented towards human reading. |
|
Figure. The syntax tree of the web document with the root made up by the html element. |
|
Tree processing (2) Slide Annotated slide Contents Index References Textbook |
|
Program: The link extraction functions. |
|
Program: A link extraction dialogue. |
|
Exercise 3.3. The function outline-copy | Program a function outline-copy which makes a deep copy of a list structure. Non-list data in the list should all be translated to a symbol, such as '-. You should be able to handle both proper lists and improper lists. As an example: (outline-copy '((a b c) (d e . f) (h i))) => ((- - -) (- - . -) (- -)) |
|
Recursion versus iteration Slide Annotated slide Contents Index References Textbook |
|
The concept tail recursion: Tail recursion is a variant of recursion in which the recursive call takes place without contextual, surrounding calculations in the recursive function. | A tail call is the last 'thing' to be done before the function returns. Therefore there is no need to maintain any activation record of such a call - we can reuse the previous activation record. The image series below will illustrate this. |
Image series: A recursive formulation of the function fak and the accompanying recursive process | A recursive formulation of the function fak and the accompanying recursive process |
Image no. 1. The recursion is developed - activation records are stacked |
Image no. 2. The recursion is developed - activation records are stacked |
Image no. 3. The recursion is developed - activation records are stacked |
Image no. 4. The recursion is developed - activation records are stacked |
Image no. 5. The turning point is reached - now on to actual multiplication |
Image no. 6. Trivial multiplication with 1 |
Image no. 7. Yet another time |
Image no. 8. Multiplication with 2 |
Image no. 9. Multiplication with 3 |
Image no. 10. Multiplication with 4 |
Image series: A tail recursive formulation of the function fak and the accompanying iterative process without memory optimization | A tail recursive formulation of the function fak and the accompanying iterative process without memory optimization |
Image no. 1. The recursion develops - multiplication with 4 |
Image no. 2. The recursion develops - multiplication with 3 |
Image no. 3. The recursion develops - multiplication with 2 |
Image no. 4. The recursion develops - multiplication with 1 |
Image no. 5. Turning point - we have the result in r |
Image no. 6. Non-productive unstacking |
Image no. 7. Non-productive unstacking |
Image no. 8. Non-productive unstacking |
Image no. 9. Non-productive unstacking |
Image no. 10. Non-productive unstacking |
Image series: A tail recursive formulation of the function fak and the accompanying, memory optimized iterative process | A tail recursive formulation of the function fak and the accompanying, memory optimized iterative process |
Image no. 1. Multiplication with 4 |
Image no. 2. Multiplication with 3 - frame reused |
Image no. 3. Multiplication with 2 - frame reused |
Image no. 4. Multiplication with 1 - frame reused |
Image no. 5. Done - the result is in r |
|
Example of recursion: number-interval Slide Annotated slide Contents Index References Textbook |
|
Program: The function number-interval from the general LAML library. This function returns a list of t-f+1 numbers from f to t .Try it out!. |
|
Program: The function number-interval-iter is an iterative, tail recursive variant of number-interval. |
|
Program: A sample dialogue with the number interval functions. |
|
Exercise 3.5. The append function | The function append, which is a standard Scheme function, concatenates two or more lists. Let us here show a version which appends two lists: (define (my-append lst1 lst2) (cond ((null? lst1) lst2) (else (cons (car lst1) (my-append (cdr lst1) lst2))))) We will now challenge ourselves by programming an iterative solution, by means of tail recursion. We start with the standard setup: (define (my-next-append lst1 lst2) (my-next-append-1 lst1 lst2 ...)) where my-next-append-1 is going to be the tail recursive function: (define (my-next-append-1 lst1 lst2 res) (cond ((null? lst1) ...) (else (my-next-append-1 (cdr lst1) lst2 ...)))) Fill out the details, and try out your solution. Most likely, you will encounter a couple of problems! Now, do your best to work around these problems, maybe by changing aspects of the templates I have given above. One common problem with iterative solutions and tail recursive functions is that lists will be built in the wrong order. This is due to our use of cons to construct lists, and the fact that cons operates on the front end of the list. The common medicine is to reverse a list, using the function reverse, either on of the input, or on the output. |
Exercise 3.5. A list replication function | Write a tail recursive function called replicate-to-length, which in a cyclic way (if necessary) replicates the elements in a list until the resulting list is of certain exact length. The following serves as an example: (replicate-to-length '(a b c) 8) => (a b c a b c a b) (replicate-to-length '(a b c) 2) => (a b) In other words, in (replicate-to-length lst n), take elements out of lst, cyclically if necessary, until you reach n elements. |
Examples of recursion: string-merge Slide Annotated slide Contents Index References Textbook |
|
Program: The recursive function string-merge. Notice that this function is a general recursive function.
The recursive call, emphasized above, is not in a tail position, because of the embedding in string-append. |
|
Program: An application of string-merge which converts a list of strings to a string with a given separator. This is a typical task in a web program, where a list of elements needs to be aggregated for HTML presentation purposes.
Notice the merging of a list of n elements with a list of length n-1. The function make-list is another LAML function;
(make-list n el) makes a list of n occurrences of el. |
Program: A tail recursive version of string-merge. |
|
Examples with recursion: string-of-char-list? Slide Annotated slide Contents Index References Textbook |
|
Program: The function string-of-char-list? which relies on the tail recursive function string-of-char-list-1?.
The function string-of-char-list-1? iterates through the characters in str, via the controlling parameters i and lst. |
|
Program: Applications of string-of-char-list?. The function blank-string? determines if a string is formed entirely of white space characters.
The function numeric-string? is a predicate that returns true if the string consists exclusively of decimal digits. This is, for instance,
useful to check the form input of dates and time in some server-based web applications. The version of numeric-string? in the lib/general.scm
of LAML is slightly more general than the version shown above (it allows + or - signs as well, depending on an optional parameter). |
|
Exercises Slide Annotated slide Contents Index References |
|
Exercise 3.6. Sublists of a list | In this exercise we will program a function front-sublist which returns the first n elements of a list. The signature (the head) of the function should be (front-sublist lst n) where lst is a list and n is a number. As a precondition it can be assumed that lst is a proper list and that n is a non-negative integer. As a postcondition we want to guarantee that the length of the result is n. As an example (front-sublist '(a b c d e) 3) => (a b c) (front-sublist '(a b c d e) 6) => ERROR First, identify the extreme, border cases and be sure that you know how to handle these. Next, program the function with due respect to both the precondition and the postcondition. Next, test the function carefully in a dialogue with your Scheme system. Given the function front-sublist we will program the function sublists, which breaks a proper list into a list of sublists of some given size. As an example (sublists '(a b c d e f) 3) => ((a b c) (d e f)) Program the function sublists with use of front-sublist. Be careful to prepare you solution by recursive thinking. It means that you should be able to break the overall problem into a smaller problem of the same nature, as the original problem. You should feel free to formulate both preconditions and postconditions of the function sublists, such that the existing function front-sublist fits well. Hint: The Scheme function list-tail is probably useful when you program the function sublists. A table can be represented as a list of rows. This is, in fact, the way tables are represented in HTML. The tr tag is used to mark each row; the td tag is used to mark each cell. The table tag is used to mark the overall table. Thus, the list of rows ((a b c) (d e f)) will be marked up as: <table> <tr> <td>a</td> <td>b</td> <td>c</td> </tr> <tr> <td>d</td> <td>e</td> <td>f</td> </tr> </table> Write a Scheme function called table-render that takes a list of rows as input (as returned by the function sublists, which we programmed above) and returns the appropriate HTML rendering of the rows. Use the LAML mirror functions table, tr, and td. Be sure to call the LAML function xml-render to see the textual HTML rendering of the result, as opposed to LAML's internal representation. Notice: During the course we will see better and better ways to program table-render. Nevertheless, it is a good idea already now to program a first version of it. |
Example of recursion: Hilbert Curves |
Hilbert Curves Slide Annotated slide Contents Index References Textbook |
The concept Hilbert Curve: The Hilbert Curve is a space filling curve that visits every point in a square grid |
A hilbert curve of order 5 which is traversed repeatedly to emphasize the maze. The view enforced on you through this picture is an iterative one: We traverse the curve one edge after the other. Needless to tell, this gives a very confusing and complicated understanding of the curve. Below, we will explain the curve in recursive terms. It turns out that this will be key to understanding the curve. Relative to the Scheme program shown later, this curve is produced by the call (hilbert 5 'up) . |
|
|
Building Hilbert Curves of order 1 Slide Annotated slide Contents Index References Textbook | Here we will study the recursive composition of the most simple Hilbert Curve. |
|
In the starting point we have a Hilbert Curve of order 0 - that is nothing. It is empty. For illustrative purpose, the empty Hilbert Curve of order 0 is shown as a small circle. We see how four instances (which in the starting point are overlapping in the middle of the picture) are moved to the four corners. Finally the four Curves of order 0 are connected by three connector lines. This makes up a Hilbert Curve of order 1. Relative to the Scheme program shown later, this curve can be produced by the call (hilbert 1 'up) . |
Building Hilbert Curves of order 2 Slide Annotated slide Contents Index References Textbook | Here will study the recursive composition of Hilbert Curves in additional details. |
|
In the starting point we have a Hilbert Curve of order 1, as constructed above. We see how four instances (which in the starting point are overlapping in the middle of the picture) are moved to the four corners. Two of them are rotated. Finally the four Curves of order 1 are connected by three connector lines. This makes up a Hilbert Curve of order 2. Relative to the Scheme program shown later, this curve is produced by the call (hilbert 2 'up) . |
Building Hilbert Curves of order 3 Slide Annotated slide Contents Index References Textbook | In the same way we made a Hilbert Curve of order 2, we will here see how a Hilbert Curve of order 3 is made. |
|
In the starting point we have a Hilbert Curve of order 2, as constructed above. We see how four instances (which in the starting point are overlapping in the middle of the picture) are moved to the four corners. Two of them are rotated. Finally the four Curves of order 2 are connected by three connector lines. This makes up a Hilbert Curve of order 3. Relative to the Scheme program shown later, this curve can be produced by the call (hilbert 3 'up) . |
Building Hilbert Curves of order 4 Slide Annotated slide Contents Index References Textbook | In the same way we made a Hilbert Curve of order 3, we will here see how a Hilbert Curve of order 4 is made. This is the final development along these lines in this material. |
|
In the starting point we have a Hilbert Curve of order 3, as constructed above. We see how four instances (which in the starting point are overlapping in the middle of the picture) are moved to the four corners. Two of them are rotated. Finally the four Curves of order 3 are connected by three connector lines. This makes up a Hilbert Curve of order 4. Relative to the Scheme program shown later, this curve is produced by the call (hilbert 4 'up) . |
A program making Hilbert Curves Slide Annotated slide Contents Index References Textbook | Given our understanding of Hilbert Curves obtained from the previous pages, we will now study a computer program that generates Hilbert Curves of order n, where n is any non-negative number. |
|
Program: The function hilbert programmed in Scheme as a functional program. The function returns the path of the Hilbert Curver of order n. The parameter turn determines the rotation of the curve.
In the top level call we ask for an upward Hilbert Curve: As an example, (hilbert 3 'up) produces an upward Hilbert Curve of order 3.
The red fragments are responsible for all line drawing.
The blue fragments represent all the recursive calls of the hilbert function. Finally, the green fragment represent the level 0
'basis' case. The level 0 case returns the empty Hilbert Curve, which is literally empty (no drawing at all - no contribution
to the resulting path). What does it mean that the the program is a functional program? Well, it basically means that hilbert returns a value which can be rendered somehow by another function or procedure. The value returned
is a path, composed by concat-path. The hilbert function
does not carry out any action itself. |
|
Program: The complete Hilbert programs including SVG details. |
Program: A simple Scheme path library developed for SVG. |
|
Continuations |
Introduction and motivation Slide Annotated slide Contents Index References Textbook | We start by motivating our interest in continuations. One part of the story is the usefulness of a mechanism that allows us to 'jump out of a deep subexpression'. Another part is the possibility of controlling and manipulating the 'remaining part of the calculation' relative to some given control point. |
|
|
|
The catch and throw idea Slide Annotated slide Contents Index References Textbook |
|
Syntax: |
|
Syntax: |
|
|
|
A catch and throw example Slide Annotated slide Contents Index References Textbook | We now give a Common Lisp like example of catch and throw. |
|
Program: An example using catch and throw. Please notice that the example is not a proper Scheme program.
Catch and throw are not defined in Scheme. |
|
|
The intuition behind continuations Slide Annotated slide Contents Index References Textbook |
The concept continuation: A continuation of the evaluation of an expression E in a surrounding context C represents the future of the computation, which waits for, and depends on, the value of E |
Table. An intuitive understanding of continuations of an expression in some context. |
|
Being more precise Slide Annotated slide Contents Index References Textbook | Instead of relying of an informal understanding of continuations we will now introduce lambda expressions that represent the continuations. |
|
Table. A more precise notation of the continuations of E |
|
The capturing of continuations Slide Annotated slide Contents Index References Textbook | It is now time to introduce the Scheme primitive that allows us to capture a continuation. |
|
Table. Use of call/cc and capturing of continuations. |
|
Capturing, storing, and applying continuations Slide Annotated slide Contents Index References Textbook |
|
Table. Capturing and applying continuations. The captured continuations are stored in a global variable. The application of the continuation is shown in the third column, and the result of the application of the continuation is shown in the fourth column. |
|
Use of continuations for escaping purposes Slide Annotated slide Contents Index References Textbook |
|
Table. Capturing and use of a continuation for escaping purposes |
|
Practical example: Length of an improper list Slide Annotated slide Contents Index References Textbook |
|
Program: The function list-length, which returns the symbol 'improper-list in case it encounters an improper list. |
|
Practical example: Searching a binary tree Slide Annotated slide Contents Index References Textbook |
|
Program: A tree search function which uses a continuation found if we find what we search for. Notice that this examples requires the function subtree-list, in order to work.
The function returns #f in case we do not find node we are looking for.
Notice that it makes sense in this example to have both the if expression and the
#f value in sequence! |
|
Chapter 3: Name binding, Recursion, Iteration, and Continuations
Course home Author home About producing this web Previous lecture (top) Next lecture (top) Previous lecture (bund) Next lecture (bund)
Generated: July 2, 2013, 09:15:04