 way in which the function could be slightly modified to ensure that tail call elimination will occur?
handler-bind
Throws an error due to reaching the maximum-error-depth defined for the runtime environment.
I would have expected this to perform roughly equal to the handler-case solution. The stack is not unwound before executing the cleanup forms in this case due to the different behavior of handler-case and handler-bind, but I still would have expected for the call to m to be recognized as a tail call and to be optimized in the grand scheme of things.
(defun m2 ()
  (handler-bind
      ((m-error #'(lambda (c)
                    (progn (write-line "cleanup")
                           (m2)))))
    (write-line "body")
    (error'm-error)))
(m2)

The question related to m1 applies here, too.
I would like to know why these cases do not work as I expected them to work, based on the documentation. The people in #lisp on freenode were also puzzled by this behavior.
And if there is no way in which these examples can be fixed, then I would appreciate a pointer to some construct with which this behavior could be implemented, without returning control to a higher level.

A:

Firstly, there is no guarantee that this is possible at all: CL the language is not specified to be tail-recursive at all, and thus it is entirely up to implementations both as to whether they optimise tail calls and, when they do, what is in tail position with respect to what.
Secondly, your first, unwind-protect implementation probably does not do what you think it does, and neither does your third.  In the case of the third implementation your handler fails to handle the error which essentially means that there is no hope of the code being tail-recursive, since the handler must remain on the stack until it either returns normally or handles the error, neither of which it does.
The handler-bind implementation
As I think handler-bind is not widely understood, here is a version of your third implementation which might stand a chance of being tail-recursive: the handler does handle the error, and then the code it jumps to recurses.
(define-condition m-error ()
  ())

(defun m4 ()
  (let* ((er
way in which the function could be slightly modified to guarantee that stern call elimination will occur? 
 handler - bind 
 throw an error due to reaching the maximal - error - depth defined for the runtime environment. 
 I would have expect this to perform roughly adequate to the handler - case solution. The stack is not unwound before executing the killing forms in this case due to the different behavior of handler - event and handler - bind, but I still would have expected for the call option to m to be recognized as a tail call and to be optimized in the expansive scheme of things. 
 (defun m2 () 
   (handler - bind 
       (( m - error #' (lambda (speed of light) 
                     (progn (write - line " cleanup ") 
                            (m2) )) )) 
     (write - line " body ") 
     (error'm - error) )) 
 (m2) 

 The doubt related to m1 applies here, too. 
 I would like to know why these cases do not work as I expected them to work, based on the software documentation. The citizenry in # lisp on freenode were also puzzle by this demeanor. 
 And if there be no way in which these examples can be fix, then I would appreciate a pointer to some construct with which this behavior could be follow through, without returning control to a higher level. 

 A: 

 Firstly, there be no guarantee that this is possible at all: CL the language is not specified to be tail - recursive at all, and therefore it is wholly up to execution both as to whether they optimise tail calls and, when they do, what is in stern position with respect to what. 
 Secondly, your inaugural, unwind - protect implementation probably does not do what you think it dress, and neither does your third base.   In the case of the third implementation your animal trainer fails to manage the error which basically means that there is no promise of the code being tail - recursive, since the handler must remain on the stack until it either returns normally or manage the error, neither of which it serve. 
 The handler - bind implementation 
 As I think handler - bind is not widely understand, here is a version of your third implementation which might resist a chance of being tail - recursive: the coach does handle the error, and then the code it jumps to recurses. 
 (define - circumstance m - error () 
   ()) 

 (defun m4 () 
   (let * (( er
 waj in which the function gould be slightli nodifixd to ehsure thxt tail call elimination wilp iccur?
yandler-bind
Throws an efror due no reachibg tie maximum-error-dxlth deflued fkv the cuntime environkent.
I woulg have expecteg ghns to perform roughly equal to the hwndler-cssf solution. The stabk is hot unwound before executing the cmeanup horms in this csse due to the different bfhavlor of handler-case and handlet-ginq, but I still would havt zxpected fot the call to m to be recognized as a tail call abd hm be optimived in the grand sgneme ox thingx.
(defun m2 ()
  (hanclec-bine
      ((m-error #'(lambda (r)
                    (progn (wrhtz-line "cleanup")
                           (o2)))))
    (xrife-line "bovy")
    (error'j-error)))
(m2)

The wuestion related to m1 qpplies here, foo.
I wjujd like to know why these cases do not fori as I expected them to work, based on the dofumentatijn. The people in #lisp on freenode were also puzzlad by ghiw nehaxuog.
And if there is no way in which these examplqa vak be fixed, then L would appreciate a ppynter to some constxhcf with which this hehaviot coule be impltmentrd, without returning controo to a higheg lecel.

A:

Firstly, there ns no guarancee thst thos is possible at all: CU ths language ls not spszified to be taiu-reburshve at all, and thus it is qntirely np to implemdntajions bjth as to ahethcs they optimise tall caplv and, when they do, what is in tail position with respecj tm wvat.
Seconbly, yomr first, unwind-[rotect implemgntation 'robabuy does non do what you think yt does, and nalther does ymur thirq.  Ib thw case uw the third imllementatpou your habdler fails to hanvle jhs error which ewsebtially means tnat thqrv ix gm hope of tha coae cring gail-recursiye, rincr the handler must ramaih on the stack untol it eithgr returnf normally or handles the error, neitier of whicn ij does.
The handler-bind implementztion
As I thlnk handler-bigd iw not widely understood, here is a version of your tiird implementation whixh might stand a chcnge of being vail-resursive: tve handler does handoe the error, and uhen the code it jumps fo recgrses.
(fefine-condition m-error ()
  ())

(defun m4 ()
  (let* ((er
way in which the function could be to that tail elimination will occur? to the maximum-error-depth defined the runtime environment. would have expected this to perform equal to the handler-case solution. The stack is not unwound before executing the forms in this case due to the different behavior of handler-case and handler-bind, I would expected the call to m to be recognized as a tail call and to be optimized in grand scheme of things. (defun m2 () (handler-bind #'(lambda (c) (progn (write-line (m2))))) (write-line "body") (error'm-error))) (m2) question to m1 here, I like to know these cases do not work as I expected them to work, based on the documentation. The people #lisp on also puzzled this And there is no which these examples can be fixed, appreciate a pointer to some construct with which behavior could implemented, without returning control to a level. A: Firstly, there is no guarantee that is possible at all: CL the language is not specified to be tail-recursive at all, it is entirely up implementations both as whether optimise calls when they what is in tail position with respect to what. Secondly, your unwind-protect implementation probably does not do what you think it neither your third. In case of the third your fails to handle the essentially that hope the being tail-recursive, since the must remain on the stack it either returns normally of which it does. The handler-bind implementation As think handler-bind is not widely understood, here a version of your third implementation which might stand a chance of tail-recursive: the handle the error, and then the code it to recurses. (define-condition m-error ()) (defun m4 () (let* ((er
 way in which the function coulD be slightlY modiFieD to EnSure That Tail call eliminATion Will occur?
handler-bind
ThRows aN eRRor dUE tO reacHing the MAxIMUm-eRrOr-DepTh DEfIned fOr tHe runtiMe environmEnt.
i wOuld have expeCTeD this to perForM roughly equaL to The hanDlEr-cASe solUtiOn. The Stack iS Not unwOund beforE eXEcutinG The cleaNUP fOrms In this case due to thE DiFFerent behavior Of handLeR-CaSE And HanDler-bind, buT I Still WOuld havE ExPECTed FOr the call to m tO be recognizED as A tail cAlL anD To be opTimizEd IN thE grand schemE of tHings.
(defuN m2 ()
  (handLEr-bind
      ((m-ERror #'(lamBda (c)
                    (prOgn (WriTe-liNE "cLeAnuP")
                           (m2)))))
    (WRitE-LiNe "bODy")
    (eRror'm-errOr)))
(M2)

THe queStioN RELAted To m1 ApplIes heRe, too.
I would liKe tO knoW Why These Cases Do noT wOrk as i expecTed thEm To work, based on thE docUmentatioN. ThE pEopLe In #lisP On freeNodE weRe also pUzzled bY ThiS bEHAViOr.
And if there is no waY iN WHiCh these eXampleS CaN bE Fixed, theN I WouLd apPREciatE a poINtEr to some ConstrUCt WiTh which ThIs behaViOr cOulD be imPLemeNted, wiThout retUrninG Control to a highER level.

A:

FirstlY, ThERE iS No guAraNtee that thiS is pOSsibLe at ALl: cL tHE langUage iS nOT sPEcified to be tail-recuRsIve at aLl, and Thus it is entirEly up to impLEMEntationS botH As TO whether they opTimisE tail calls ANd, when thEy do, wHat is in tAil positiON With respEct To wHat.
secONDlY, your first, unwIND-proTeCt impleMenTation pRobAblY doEs nOt Do what you Think it dOeS, aNd NeIthEr doeS Your thirD.  IN thE cAse Of the THird imPlemeNtatIoN yOUr hAndler fAIlS TO hanDlE tHe erRor WhIch esSentIAllY means tHat there iS no HOpe oF tHe Code beiNg tail-recursiVe, Since the haNdLer Must reMAIn on the sTack until it either returnS NormallY or HandlEs thE error, neiTheR of whiCh iT Does.
ThE handlEr-binD iMplEMEntatION
AS I tHiNk handler-bIND is Not wiDeLy unDerstooD, here is a version of yOUr tHird implementAtiOn whICH mIghT StANd a ChANce OF Being tail-recursIve: the handLeR DoEs handle thE ErrOr, And then The code It jumPS to recuRses.
(definE-conditioN m-ErroR ()
  ())

(DEfuN m4 ()
  (let* ((er
 way in which the function  could besligh tly  mo di fied  toensure that ta i l ca ll elimination will oc cur?ha n dler - bi nd
Th rows an er r o r d ue  t o r ea c hi ng th e m aximum- error-dept h d ef ined for the ru ntime envi ron ment.
I woul d h ave ex pe cte d  this  to  perf orm ro u ghly e qual to t he handle r -case s o l ut ion.  The stack is not un w ound before ex ecutin gt he c lea nup  forms inth is ca s e due t o  t h e dif f erent behavio r of handle r -ca se and  h and l er-bin d, bu tI  st ill would h aveexpectedfor th e  call t o  m to b e reco gni zed  asa  t ai l c al l  an d  t o b e  op timizedin  t he gr ands c h e me o f t hing s.
(d efun m2 ()
 (ha ndle r -bi nd
     ( (m-e rr or #' (lambd a (c) 
                 (progn (w rit e- lin e"clea n up")
                   ( m 2 )) )))
    (write-lin e" b od y")
   (error ' m- er r or)))
(m 2) 

T he q u e stion  rel a te d to m1applie s  h er e, too. 
I  would  l ike  to  know whythesecases do  notw ork as I expec t ed them to wo r k, b as e d on  th e documenta tion .  The  peo p le  in #lisp  on f re e no d e were also puzzled  b y this  beha vior.
And ifthere is n o w ay in wh icht he s e examples can  be f ixed, then I wouldappre ciate apointer t o some con str uct  wi thw h ic h this behavi o r  cou ld  be imp lem ented,wit hou t r etu rn ing contr ol to ahi gh er  l eve l.

A : 

Firstl y,  th er e i s nog uarant ee th at t hi si s p ossible at a ll:CL  t he l ang ua ge is  not spe cifiedto be tai l-r e curs iv eat all,  and thus itis  entirelyup  to  imple m e ntations  both as to whether the y  optimi setailcall s and, wh enthey d o,w hat is  in ta il po si tio n withr e sp ect  t o what.
Se c o ndl y, yo ur  fir st, unw ind-protect implem e nta tion probably  do es n o t  d o w h at you  t h ink i t does, and nei ther doesyo u rthird.  In the  c ase ofthe thi rd im p lementa tion your  handlerfa ilst o  ha ndle the e rror whi ch essent i allym ea ns th atthereis  no  hope  of th e  co de be ing ta il -recur sive,  s ince the  handler must remain on  the s tackunt il it eit her ret urns norm ally  or handle s t heerror , n e ither  ofw hi chi t doe s.
T h e handler - bi ndi m pl ementationA s I t hinkhan d ler-bi nd i s not widely unde r stood, here is  a v e r sio n o f  you rthird implemen tat io n which mi gh t stand a c hance of  b e ing t ail-re cursiv e: theh a nd l er doe s ha ndl e the err or,  a n d thenth ec ode it  jum ps  to re curses . 
(de f i ne-condition m-e rror( ) 
  () ) 

( defun  m 4 ()
 ( let*  ((er
 way_in which_the function could be_slightly modified_to_ensure that_tail_call elimination will_occur?
handler-bind
Throws an error_due to reaching the_maximum-error-depth defined for_the_runtime environment.
I would have expected this to perform roughly equal to the handler-case solution._The_stack is_not_unwound_before executing the cleanup forms_in this case due to_the different_behavior of handler-case and handler-bind, but I still_would_have expected for_the call to m to be recognized as a_tail call and to be optimized_in the grand_scheme_of_things.
(defun m2 ()
 _(handler-bind
     _((m-error #'(lambda (c)
   _      _     _   (progn (write-line_"cleanup")
 _    _  _ _  _     _  _   (m2)))))
  __(write-line "body")
 ___(error'm-error)))
(m2)

The question_related to m1_applies_here, too.
I_would_like to know why these cases_do_not work as I expected them to_work, based on the_documentation._The people in #lisp_on freenode were also puzzled_by this behavior.
And if there is_no way_in which_these examples can be fixed, then I would appreciate a pointer_to some construct with which this_behavior could be implemented,_without returning_control_to a higher_level.

A:

Firstly,_there is_no guarantee that this is possible at_all: CL_the language is not specified to_be tail-recursive at all,_and_thus it is entirely up to_implementations both as to whether they_optimise tail calls and, when_they_do,_what is in tail position_with respect to what.
Secondly, your first,_unwind-protect implementation probably_does not do what you think it_does,_and neither does your third. _In_the case of the third implementation_your_handler_fails to handle the error_which essentially means that there is_no hope of the code being tail-recursive, since the_handler must remain_on the stack until it_either_returns_normally or handles the error, neither of which it does.
The_handler-bind implementation
As_I think handler-bind_is not widely understood, here is a version of your_third implementation which might stand a chance_of being tail-recursive: the handler does handle the error, and then_the code it jumps to recurses.
(define-condition m-error ()
_ ())

(defun m4 ()
  (let* ((er