Accessing the depth of the call stack in a diagram
Racket allows you to store values ββon the call stack. You can use this to track depth. This is how I would do it:
#lang racket
;;; This module holds the tools for keeping track of
;;; the current depth.
(module depth racket
(provide (rename-out [depth-app #%app])
current-depth)
(define (extract-current-continuation-marks key)
(continuation-mark-set->list (current-continuation-marks) key))
(define (current-depth)
(car (extract-current-continuation-marks 'depth)))
(define-syntax (depth-app stx)
(syntax-case stx ()
[(_depth-app proc args ...)
#'(let ([p (with-continuation-mark 'depth (+ (current-depth) 1)
proc)]
[as (with-continuation-mark 'depth (+ (current-depth) 1)
(list args ...))])
(apply p as))])))
;;; Importing the #%app from the depth module will override
;;; the standard application to use depth-app which keeps
;;; track of the depth.
(require 'depth)
(with-continuation-mark 'depth 0 ; set the initial depth to 0
(let ()
;;; Example: foo is tail recursive
(define (foo n)
(displayln (list 'foo n (current-depth)))
(if (< n 5)
(foo (+ n 1))
'done))
;;; bar is not tail recursive
(define (bar n)
(displayln (list 'bar n (current-depth)))
(if (< n 5)
(cons n (bar (+ n 1)))
'()))
;;; Call the examples
(foo 0)
(bar 0)))
Output:
(foo 0 2) (foo 1 2) (foo 2 2) (foo 3 2) (foo 4 2) (foo 5 2) (bar 0 2) (bar 1 3) (bar 2 4) (bar 3 5) (bar 4 6) (bar 5 7) '(0 1 2 3 4)
The output shows that the depth is not increasing at foo
and that it is at bar
.
source to share
There is no standard way to do this.
Optimizing tail calls == increasing call stack. You demonstrate this by writing something that would normally hit the stack and run it.
You can get a short stack trace when you signal an error, but what it looks like is injection specific.
In CL, you can keep track of functions and you won't see the output of sequential tail calls when optimizing the tail call.
Lazy languages ββdon't need tail recursion, as evaluation is by necessity.
source to share