Reputation: 55
[solved]
I have something similar with these four functions: base
, init
, func
and some
. The func
is recursive and calls itself: in the "stop case" it would call some
and return its value, then it should return control back to "init
", wherefrom it is invoked; the latter being once called from base
.
base
-> init
-> func
-> init
-> func
-> some
|
_________+
|
v
; should continue from here (in `func`)
[not anymore]
Instead, after the first call to some
, the control is yielded directly to base
, skipping what I would expect to be the intermediate (init,func)
pair call(s).
I actually tried several simpler cases using block
, return
and recursion (e.g., "mutual tail-recursive factorial
"), and all worked well. I mention that func
uses a test
helper function that catch
a throw
(but I tried even an example with (catch 'test (throw 'test 0))
, and it was ok); just so whatever could my real program have something causing the issue.
This is elisp
: each defun
commences with block
, and all functions use return
, as in the following.
[I switched from using "defun
/block
" to "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)
The pack
variable is my value-list
as data structure. I also use func
to reiterate itself (in tail-recursive call) with a special accumulating-parameter so that I avoid "imperative" while
.
So instead of what I would expect (each >
is paired by <
)
base->
init->
func->
init->
func->
some->
<-some
<-func
<-init
func-> ; tail-recursion
<+func
<1func
<-init
<-base
my program behaves as follows.
base
-> init
-> func
-> init
-> func
-> some
|
__________________________+
|
v
; control yielded here (to `base`)
[not anymore]
Why is the control yielded too soon back to the start of the program, and not continue in the first call to func
, after return
from the second call via init
?
Appreciate any help,
Sebastian
Upvotes: 2
Views: 152
Reputation: 55
Thanks both for your answer: inserting into my program those messages I tried as with the code I added for explanations revealed there are no defun*
problems with elisp
, but some things I mistook in design.
Upvotes: 0
Reputation: 29011
Looking at your code, it is not clear to me what's the extent of the block in func
. If the block includes the whole func
definition, then yes, the control reaches func
when returning, but the block is skipped completely, hence the function completely, and comes back all the way up where it was called (eventually base
). May be that the case?
If that's so, you have to put the code that you want to execute after a return after the block.
EDIT: Looking again at your code, I think you're not using the return
as it should be used. For instance in init
you have
(block nil
...
(return (func ...)))
This return
"cancels" the block, and takes the same effect as not having the block at all, unless some function called in "...
" does have a return
without a block
. So the return
here cancels the possible return points of func
.
Upvotes: 1