scheme# How does the named let in the form of a loop work?

In an answer which explains how to convert a number to a list the `number->list`

procedure is defined as follows:

```
(define (number->list n)
(let loop ((n n)
(acc '()))
(if (< n 10)
(cons n acc)
(loop (quotient n 10)
(cons (remainder n 10) acc)))))
```

Here a "named `let`

" is used. I don't understand how this named `let`

works.

I see that a loop is defined where the variable `n`

is equal to `n`

, and the variable `acc`

equal to the empty list. Then if `n`

is smaller than 10 the `n`

is consed to the acc. Otherwise, "the loop" is applied with `n`

equal to `n/10`

and `acc`

equal to the cons of the remainder of `n`

/10 and the previous accumulated stuff, and then calls itself.

I don't understand why `loop`

is called loop (what is looping?), how it can automatically execute and call itself, and how it will actually add each number multiplied by its appropriate multiplier to form a number in base 10.

I hope someone can shine his or her light on the procedure and the above questions so I can better understand it. Thanks.

Solution

The basic idea behind a named `let`

is that it allows you to create an internal function, that can call itself, and invoke it automatically. So your code is equivalent to:

```
(define (number->list n)
(define (loop n acc)
(if (< n 10)
(cons n acc)
(loop (quotient n 10)
(cons (remainder n 10) acc))))
(loop n '()))
```

Hopefully, that is easier for you to read and understand.

You might, then, ask why people tend to use a named `let`

rather than defining an internal function and invoking it. It's the same rationale people have for using (unnamed) `let`

: it turns a two-step process (define a function and invoke it) into one single, convenient form.

It's called a loop because the function calls itself in *tail position*. This is known as tail recursion. With tail recursion, the recursive call returns directly to your caller, so there's no need to keep the current call frame around. You can do tail recursion as many times as you like without causing a stack overflow. In that way, it works exactly like a loop.

If you'd like more information about named `let`

and how it works, I wrote a blog post about it. (You don't need to read it to understand this answer, though. It's just there if you're curious.)

- How to make `set!` change the variable in `let` (Scheme)?
- Inheritance classes in Scheme
- How do I get the functions put and get in SICP, Scheme, Exercise 2.78 and on
- Trouble understanding / visualising SICP streams Hamming numbers program
- Unbound variable error in cube root function
- Scheme - Replacing elements in a list with its index
- What is the relation of parent env and the child env in MIT-Scheme?
- conda, condi, conde, condu
- Pipe-Function in scheme
- DrRacket: atom? and symbol? undefined - What's wrong?
- curry in scheme
- What are some good ways of implementing tail call elimination?
- How do I perform basic file I/O operations Scheme?
- One way to construct graph adjacency list based on adjacency pairs similar to `fold` in MIT Scheme
- Graph programming in Scheme
- "The object square is not applicable" but `square` is one internal procedure in MIT-Scheme
- How is nested variable argument interpreted in Scheme?
- Advantages of "typed Racket" over Racket
- Typed Racket - dynamic function calls (string to procedure) revisited
- How to use symbolic expressions produced by a function to define another function?
- Create an infinite stream from a list
- Why does Scheme use the procedural representation of pairs?
- Implementing a "Pythonic" map in Scheme: bad idea?
- Store external data in guile modules?
- Scheme: Returning two largest numbers from a set of three numbers
- `1.0+1e-100=1.` in MIT-scheme
- Scheme merge two lists into one
- How to recursively reverse a list using only basic operations?
- What's the proper scheme file extension?
- How to obtain my function definition in MIT Scheme?