为了演示尾递归的有效性,我想在Scheme中动态访问调用堆栈的深度。
有办法做到这一点吗?如果没有,有没有办法在其他主要功能语言(OCaml,Haskell等)中执行此操作?
答案 0 :(得分:3)
没有标准的方法。
尾调用优化==没有调用堆栈增加。您可以通过编写通常会破坏堆栈并运行它来演示它。
当发出错误信号时,您可能会得到一个短堆栈跟踪,但它的外观如何是特定于实现的。
在CL中,您可以跟踪函数,并且当尾部调用优化后,您将看到连续尾调用没有输出。
懒惰语言不需要尾递归,因为需要进行评估。
答案 1 :(得分:2)
Racket允许您在调用堆栈中存储值。 您可以使用它来跟踪深度。 我将如何做到这一点:
#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)))
输出结果为:
(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)
输出显示foo
中的深度不会增加,而bar
中的深度不会增加。