---
title: Eboard 23  Naming local procedures
number: 23
section: eboards
held: 2018-03-14
link: true
---
CSC 151.01, Class 23:  Naming local procedures
==============================================

_Overview_

* Preliminaries
    * Notes and news
    * Upcoming work
    * Extra credit
    * Questions
* Review of reading
* Lab
* Debrief

Preliminaries
-------------

### News / Etc.

* New partners!
* Happy pi day!
* We will have one mentor session this week at 7pm on Thursday.
  The intent is more of an opportunity to talk broadly about CS
  than about the quiz.  (A panel of mentors.)
* RIP Stephen Hawking.  
* I hope to distribute an answer key to HW6 tonight.
* You are awesome.

### Upcoming work

* [Lab writeup for class 23](../writeups/writeup23): Exercise 2.
  Due before class Friday..
* Reading for Friday 
    * [Randomness](../readings/randomness)
* No homework over break.
* [Flash Cards](../flashcards/flashcards08) due TONIGHT.
* Quiz Friday: Identify your classmates.

### Extra credit (Academic/Artistic)

* Visit the two exhibits at the Faulconer Gallery.

### Extra credit (Peer)

### Extra credit (Recurring peer)

* Listen to KDIC Wednesdays at 6pm - Witty banter with other 
  personalities and/or co-host.  Also Indian, Arabic, and Farsi music.  
  (Up to two units of extra credit.)
* Peer editing with SS.  Talk to SS about the details.  Make your
  English Lit more literate.

### Extra credit (Misc)

* Host one or more prospective students.  

### Other good things

### Questions

_How do I decide whether to use direct recursion or helper recursion?_

> Use helper recursion if (a) your analysis of the problem suggests
  that an extra parameter will be useful; (b) you find it particularly
  natural to think about recursion in terms of building up a solution as
  you go; or (c) the "draw a table" approach seems productive to you.

> Use direct recursion if the solution to a "simpler" version of the
  problem leads naturally to a solution to the whole problem.
  "Trust the magic recursion fairy."

> When I'm trying to build lists that appear in the same order as the
  original, I am more likely to use direct recursion.

_Can we do an example?_

> Sure.  We did `tally-odds` and `iota` on the board.  Here's our
  *incorrect* version of `iota`

```
(define iota
  (lambda (n)
    (iota-helper '() 0 n)))
(define iota-helper
  (lambda (so-far i n)
    (if (>= i n)
        so-far
        (iota-helper (cons so-far i)
                     (+ 1 i)
                     n))))
```

> That one didn't work so well.

```
(define iota
  (lambda (n)
    (iota-helper '() 0 n)))
(define iota-helper
  (lambda (so-far i n)
    (if (>= i n)
        so-far
        (iota-helper (cons so-far i)
                     (+ 1 i)
                     n))))
```

> We realized that `cons` takes a value and a list, not a list and a value.

```
(define iota
  (lambda (n)
    (iota-helper '() 0 n)))
(define iota-helper
  (lambda (so-far i n)
    (if (>= i n)
        so-far
        (iota-helper (cons i so-far)
                     (+ 1 i)
                     n))))
```

> When we tried it, we found that we got the values in reverse order.

```
> (iota 5)
'(4 3 2 1 0)
```

> So we added a call to `reverse`

```
(define iota
  (lambda (n)
    (reverse (iota-helper '() 0 n))))
```

> We tried using `append` instead.

```
(define iota
  (lambda (n)
    (iota-helper '() 0 n)))
(define iota-helper
  (lambda (so-far i n)
    (if (>= i n)
        so-far
        (iota-helper (append so-far (list i))
                     (+ 1 i)
                     n))))
```

> This version worked fine.  But Sam said "I don't like the use of `append`
  in recursive procedures."

> Sam also noted that this may be a case in which direct recursion is better.

_I hear that you don't like `append`.  Why?_

> It's similar to the `(= (length lst) 1)` issue.  `append` turns out
  to be an expensive operation.  Let's look at how we might write it.

> `(define join-two-lists (lambda (lst1 lst2) ...))`

> I'm building a list, so I likely want to try direct recursion.  I'll
  need to figure out which list to simplify.

> We recurse over the first list.  If the recursive case works, we can
  then use `cons` to add the first thing back in.

> When are we done?  When the first list is empty.

> `(join-two-lists null some-list)` gives back `some-list`

```
; Just like append, but we defined it ourselves
(define join-two-lists
  (lambda (lst1 lst2)
    (if (null? lst1)
        lst2
        (cons (car lst1)
              (join-two-lists (cdr lst1) lst2)))))
```

_Why does this work?_

```
   (join-two-lists '(3 1 4) '(1 5 9))
=> (cons 3 (join-two-lists '(1 4) '(1 5 9)))
=> (cons 3 (cons 1 (join-two-lists '(4) '(1 5 9))))
=> (cons 3 (cons 1 (cons 4 (join-two-lists '() '(1 5 9)))))
=> (cons 3 (cons 1 (cons 4 '(1 5 9))))
=> (cons 3 (cons 1 '(4 1 5 9)))
=> (cons 3 '(1 4 1 5 9))
=> '(3 1 4 1 5 9)
```

> Now let's go back to `iota` and assume we wrote it with append.

> `(append '() (list 0))` - Fast.  One call to cons to build `(list 0)`

> `(append '(0) (list 1))` - One call to cons to build `(list 1)`  One
  recursive call in append gives another cons.  Two calls to cons.

> `(append '(0 1) (list 2))` - Three calls to cons

> `(append '(0 1 2) (list 3))` - four calls to cons

> To build `'(0 1 2 3)` took ten call to `cons`.

> To build `'(0 1 2 3 4)` took fifteen calls to `cons`.

> To build `'(0 1 2 3 4 5)` took twenty-one calls to `cons`.

> To build `(iota 100)` will take approximately 5050 calls to `cons`.
  In contrast, our model with `reverse` will take approximately 200 calls.
  That's a big difference.

_So I should avoid "expensive" operations in the middle of recursive
procedures?_

> In general, yes.  Sometimes it's unavoidable.

Lab
---

Can we use `all` and `any`?  Certainly.

*Writeup: Exercise 2.*

_What's going on with named let?_

```
(let NAME ([PARAM1 VAL1]
           [PARAM2 VAL2]
           ...)
  BODY)
````

Named let is a different way to define/run procedures.  It defines a procedure
with the given name, parameters, and body.  It also calls the procedure
with the given values.

Debrief
-------

Next class, we'll talk a bit more about named let.

Next class, we'll look at the different ways people approached problem 2,
particularly the different places they put the kernel.

```
(define ff0
  (letrec ([kernel ...])
    (lambda (lst)
      (cond
        ...))))

(define ff0
  (lambda (lst)
    (letrec ([kernel ...])
      (cond 
        ...))))

(define ff0
  (lambda (lst)
    (cond
      ...
      [else
       (letrec ([kernel ...])
         ...)])))
```

Which do you prefer?  Why?

Which is easiest to change to named let?

Q from student: Can't I just use an internal `define`?  Nope.
