Hacker News new | ask | show | jobs
by moefh 78 days ago
I'm not sure how this would be useful in Rust, but macros and tail calls are what allows one to (for example) write iterative loops in Scheme, which doesn't have a native loop syntax.

Maybe the same idea can be used in Rust where some constructs are easier to write in recursive form instead of a loop?

In any case, here's a silly example of a `for-loop` macro in Scheme using a tail call:

    (define-syntax for-loop
      (syntax-rules ()
        ((for-loop var start end body ...)
         (letrec ((loop (lambda (var)
                          (unless (>= var end)
                            body ...
                            (loop (+ var 1))))))  ; <-- tail call
           (loop start)))))
And here's how you'd use it to print the numbers 0 to 9:

    (for-loop i 0 10
              (display i)
              (newline))
This macro expands to a function that calls itself to loop. Since Scheme is guaranteed to have proper tail calls, the calls are guaranteed to not blow the stack.

(Note that you'll probably never see a `letrec` used like this: people would use a named `let`, which is syntax sugar for that exact usage of `letrec`. I wrote it the `letrec` way to make the function explicit).

1 comments

Interesting, my lack of real experience in Scheme will make this take a bit more work for me to fully work through the implications of. It's not immediately clear to what this would mean for Rust, since there is already a loop construct (well, three of them, although two of them are syntactic sugar for the first). You could define a macro around it in Rust today, but it would be fairly uninteresting: https://play.rust-lang.org/?version=stable&mode=debug&editio...
Yes, I agree. Like I said, it might be useful when dealing with something that is easier to express in (tail) recursion form instead of an iteration.

Anyway, here's something more-or-less equivalent in Rust, which will blow the stack if made to loop too many times: https://play.rust-lang.org/?version=stable&mode=debug&editio...

(There may be a way to use a closure instead of a function to avoid hard-coding the type of `$i` in the macro, but I can't find an easy way to write a recursive closure call in Rust).