Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>From some of Kent's students, I have learned the following: <code>letrec</code> is implemented in terms of <code>let</code> using macro expansion. It expands the <code>letrec</code> into a <code>let</code> that uses <code>set!</code> inside. So your first example would expand to this:</p> <pre><code>(let ([sum (void)]) (set! sum (lambda (x) (if (zero? x) 0 (+ x (sum (- x 1)))))) (sum 5)) </code></pre> <p>Your second, similarly (note that the nested <code>let</code>s are a result of the <code>let*</code> - also, this may not be a completely correct expansion, but is my best guess):</p> <pre><code>(let ([sum (void)] (set! sum (lambda (x) (if (zero? x) 0 (+ x (sum (- x 1)))))) (let [f (void)] (set! f (lambda () (cons n n-sum))) (let [n (void)] (set! n 15) (let [n-sum (void)]) (set! n-sum (sum n)) (f)) </code></pre> <p>I am not 600% sure how the named <code>let</code> expands, but Eli suggests that it would be implemented in terms of <code>letrec</code> itself (which makes sense and should be pretty obvious). So your named <code>let</code> moves from a named <code>let</code> into a <code>letrec</code> into an unnamed <code>let</code>. And your rewrite of the second looks almost exactly like the expansion of it anyway.</p> <p>If you are interpreting it and looking for good performance, I would lean toward the <code>letrec</code> because it is one shorter macro-expand step. Also, <code>let</code> gets turned into a lambda so you're using <code>define</code>s in your second example instead of <code>set!</code>s (which may be heavier).</p> <p>Of course, if you're compiling, it will probably all fall out in the compiler anyway so just use whichever you think looks nicer (I'm partial to <code>letrec</code> because <code>let</code> loops remind me of imperative programming but ymmv). That said, it should be up to you, stylistically (since they are more or less equivalent).</p> <p>That said, let me provide you an example that you may find worthwhile:</p> <pre><code>(letrec ([even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))] [odd? (lambda (n) (if (zero? n) #f (even? (- n 1))))]) (even? 88)) </code></pre> <p>Using your internal <code>define</code> style will yield:</p> <pre><code>(let () (define even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (define odd? (lambda (n) (if (zero? n) #f (even? (- n 1))))) (even? 88)) </code></pre> <p>So here the <code>letrec</code> code is actually shorter. And, honestly, if you're doing to do something like the latter, why not settle for <code>begin</code>?</p> <pre><code>(begin (define even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (define odd? (lambda (n) (if (zero? n) #f (even? (- n 1))))) (even? 88)) </code></pre> <p>I suspect that <code>begin</code> is more of a built-in and, as such, will not get macro-expanded (like <code>let</code> will). Finally, <a href="https://stackoverflow.com/questions/2060744/scheme-what-are-the-benefits-of-letrec">a similar issue</a> has been raised on the Lisp stack overflow a bit ago with more or less the same point. </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload