Functional Problem Solving (CSC 151 2015S) : Outlines

Outline 32: Naming Local Procedures


Held: Monday, 30 March 2015

Back to Outline 31 - Numeric Recursion. On to Outline 33 - Turtle Graphics.

Summary

We explore why and how one writes local recursive procedures.

Related Pages

Overview

Administrivia

Upcoming Work

Extra Credit Opportunities

Academic

Peer Support (Morning Section)

Peer Support (Afternoon Section)

Miscellaneous

Notes on Exam 2

Husk and Kernel Programming

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