How does named let work in a loop?

In response , which explains how to convert a number to a list, the procedure number->list is defined as follows:

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

Used here with the name let ". I do not understand how this name let works.

I see that the loop is defined where n is n and acc is null. Then, if n less than 10, then n is impl. Otherwise, the "cycle" is applied with n equal to n/10 and acc equal to the minuses of the remaining part of n / 10 and the previous accumulated material, and then calls itself.

I don’t understand why loop is called loop (what is a loop?), How can it automatically execute and call itself, and how will it actually add each number times the corresponding factor to form a number in base 10.

I hope that someone will be able to illuminate his or her light on the procedure and the above issues so that I can better understand this. Thanks.

+5
source share
2 answers

The basic idea of ​​named let is that it allows you to create an internal function that can call itself and automatically call it. So your code is equivalent:

 (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 '())) 

I hope you find it easier to read and understand.

Then you may ask why people usually use the named let rather than defining an internal function and calling it. This is the same thing people use to use (without a name) let : it turns a two-step process (defines a function and calls it) into one convenient form.


It is called a cycle because a function calls itself in the tail position. This is called a recursion tail . With tail recursion, the recursive call is returned directly to your caller, so there is no need to maintain the current call frame. You can recursively tail as many times as you want without calling. Thus, it works just like a loop.


If you need more information about the let name and how it works, I wrote a blog post about it . (However, you do not need to read this to understand this answer. It is simple if you are interested.)

+8
source

The usual use of let can be called an anonymous procedure call:

 (let ((a 10) (b 20)) (+ ab)) ;; is the same as ((lambda (ab) (+ ab)) 10 20) 

The named let simply associates this procedure with a name in the scope of the procedure, so that it is equal to one letrec procedure:

 (let my-chosen-name ((n 10) (acc '())) (if (zero? n) acc (my-chosen-name (- n 1) (cons n acc)))) ; ==> (1 2 3 4 5 6 7 8 9 10) ;; Is the same as: ((letrec ((my-chosen-name (lambda (n acc) (if (zero? n) acc (my-chosen-name (- n 1) (cons n acc)))))) my-chosen-name) 10 '()) ; ==> (1 2 3 4 5 6 7 8 9 10) 

Note that the body of a valid value is simply assigned to a named procedure so that the name is not in the first call environment. So you can do this:

 (let ((loop 10)) (let loop ((n loop)) (if (zero? n) '() (cond n (loop (- n 1))))) ; ==> (10 9 8 7 6 5 4 3 2 1) 

the loop procedure is only in the body environment of let and not a shadow variable loop when let is evaluated first.

In your example, the name loop is just a name. In a circuit, each loop ultimately runs with recursion, but usually this name is used when it returns a tail and, therefore, an iterative process.

+3
source

All Articles