2012-12-17 171 views
2

[解決]遞歸函數的返回工作不

我有這四個功能類似的東西:baseinitfuncsome。該func是遞歸調用自身:在「停止案」它會叫some並返回它的值,那麼它應該回報控制權交還給「init」,從那裏它被調用;後者曾被稱爲base

base 
    -> init 
     -> func 
      -> init 
       -> func 
         -> some 
        | 
      _________+ 
      | 
      v 
      ; should continue from here (in `func`) 

[不再]

相反,在第一次調用some後,控制直接產生於base,跳過我期望爲中間(init,func)對呼叫(一個或多個)。

其實,我試了幾個簡單的情況下使用blockreturn和遞歸(例如,「互尾遞歸factorial」),和所有運作良好。我提到func使用test幫助功能,catch a throw(但我甚至嘗試過與(catch 'test (throw 'test 0))的例子,它沒問題);只是因爲我的真實程序會導致問題。

這是elisp:每個defun開始block,並且所有功能使用return,如下所示。

[I使用 「defun/block」 切換爲 「defun*」]

(defmacro 4+ (number) 
    "Add 4 to NUMBER, where NUMBER is a number." 
    (list 'setq number (list '1+ (list '1+ (list '1+ (list '1+ number)))))) 

(defmacro 4- (number) 
    "Subtract 4 from NUMBER, where NUMBER is a number." 
    (list 'setq number (list '1- (list '1- (list '1- (list '1- number)))))) 

(defun mesg (s &optional o) 
    "Use ATAB to tabulate message S at 4-multiple column; next/prev tab if O=1/0." 
    (when (null o) (setq o 0)) 
    (case o (0 (4- atab)) (1 nil)) 
    (message (concat "%" (format "%d" (+ atab (length s))) "s") s) 
    (case o (0 nil) (1 (4+ atab)))) 

(defun* base() 
    (let (pack) 
    (setq atab 0) 
    (mesg "base->" 1) 
    (setq pack (init)) 
    (mesg "<-base"))) 

(defun* init() 
    (mesg "init->" 1) 
    (return-from init (progn (setq temp (func)) (mesg "<-init") temp))) 

(defun* func (&optional pack) 
    (mesg "func->" 1) 
    (when (not (null pack)) (return-from func (progn (mesg "<+func") pack))) 
    (when (< 0 (mod (random) 2)); stop case 
    (return-from func (progn (setq temp (some)) (mesg "<-func") temp))) 
    (setq pack (init)) 
    (case (mod (random) 2) 
    (0 (return-from func (progn (mesg "<0func") pack))) 
    (1 (return-from func (progn (setq temp (func pack)) (mesg "<1func") temp))) ; use tail-recursion instead of `while' 
    (t (error "foo bar")))) 

(defun* some() 
    (mesg "some->" 1) 
    (return-from some (progn (mesg "<-some") (list 2 3 4)))) 

(base) 

pack變量是我的值 - list作爲數據結構。我還使用func來重申自己(在尾遞歸調用中)使用一個特殊的累加參數,以便我避免「命令」while

所以不是我期望(每個><配對)

base-> 
    init-> 
     func-> 
      init-> 
       func-> 
        some-> 
        <-some 
       <-func 
      <-init 
      func-> ; tail-recursion 
      <+func 
     <1func 
    <-init 
<-base 

我的程序的行爲如下。

base 
    -> init 
     -> func 
      -> init 
       -> func 
         -> some 
          | 
__________________________+ 
| 
v 
; control yielded here (to `base`) 

[不再]

爲什麼對照產生太快返回到程序的開始,而不是繼續在第一次調用funcreturn後,從第二個呼叫通過init

得到任何幫助,

塞巴斯蒂安

+0

對不起,我現在放了一些''。 – sjb

+0

@Stefan:換句話說,是否有一些以前遇到過的[e] lisp的函數/部分/問題*已知*可能與'block' /'return'技術有最少的交互? (即函數'string-match' ...?)。我有一個公共倉庫中的代碼,但最終目的只有20%,並且它與解析'LaTeX'代碼行有關。 – sjb

回答

1

看你的代碼,這是我不明白什麼是在func塊的程度。如果該塊包含整個func定義,那麼是的,控制在返回時達到func,但該塊被完全跳過,因此該功能完全,並且一直回到調用它的位置(最終爲base)。可能是這種情況?

如果是這樣的話,你必須把你想要在代碼塊後面執行的代碼放回去。

編輯:再看看你的代碼,我認爲你沒有使用return,因爲它應該被使用。例如,在init你有

(block nil 
... 

(return (func ...))) 

return「取消」塊,並採取爲不具有除非一些功能稱爲「...」確實有return沒有塊可言,同樣的效果 a block。因此return這裏取消了func的可能返回點。

+0

我的意思是'block'包裝了所有其他的代碼,包括任何[unconditioned]'return'和條件'return'「points」,所以取消了其餘部分,但不是'block'代表'defun'返回的值。 ,現在的一個,而不是幻影。 – sjb

+0

你究竟是什麼意思?來自同一'defun' /'block'內的所有'return'點以什麼方式相互排斥? – sjb

+0

我重讀你的答案。你是對的,但是情況是'block' extent包裝了所有的函數體,就elisp解釋器而言,它就是「唯一函數」。 – sjb

0

謝謝你的回答:插入到我的程序中,我嘗試了與我爲解釋添加的代碼一樣的消息,發現elisp沒有defun*問題,但有些內容我誤以爲是設計。