在Scheme中访问调用堆栈深度

时间:2015-06-18 18:55:21

标签: functional-programming scheme tail-recursion callstack

为了演示尾递归的有效性,我想在Scheme中动态访问调用堆栈的深度。

有办法做到这一点吗?如果没有,有没有办法在其他主要功能语言(OCaml,Haskell等)中执行此操作?

2 个答案:

答案 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中的深度不会增加。