Functional Problem Solving (CSC 151 2016S) : Outlines

Outline 33: Naming Local Procedures


Held: Monday, 4 April 2016

Back to Outline 32 - Numeric Recursion. On to Outline 34 - Turtle Graphics.

Summary

We explore why and how one writes local recursive procedures.

Related Pages

Overview

Administrivia

Reminders

Upcoming Work:

Extra Credit

Academic / Artistic

Peer

Miscellaneous

Regular Peer

Misc

Far in the Future

Local Procedure Bindings

letrec

(letrec ([*name1* *exp1*]
         [*name2* *exp2*]
         ...
         [*namen* *expn*])
  *body*)

Named let

(let *name* 
  ((*param1* *exp1*)
   (*param2* *exp2*)
   ...
   (*paramn* *expn*))
  *body*)
(letrec ((*name* (lambda (*param1* ...
*paramn
*)
                  *body*)))
   (*name* *val1* ... *valn*))

An Example

(define reverse
  (lambda (lst)
    (reverse-kernel lst null)))
(define reverse-kernel
  (lambda (remaining so-far)
    (if (null? remaining)
        so-far
        (reverse-kernel (cdr remaining) (cons (car remaining) so-far)))))

The principle of encapsulation suggests that we should make reverse-kernel a local procedure.

(define reverse
  (letrec [(kernel
            (lambda (remaining so-far)
              (if (null? remaining)
                  so-far
                  (kernel (cdr remaining) (cons (car remaining) so-far)))))]
    (lambda (lst)
      (kernel lst null))))

The pattern of "create a kernel and call it" is so common that the named let exists simply as a way to write that more concisely.

(define reverse
  (lambda (lst)
    (let kernel [(remaining lst)
                 (so-far null)]
      (if (null? remaining)
          so-far
          (kernel (cdr remaining) (cons (car remaining) so-far))))))

Lab