From: Mark Tarver
Subject: throwing control within a nested conditional
Date: 
Message-ID: <1183818285.063941.88100@o61g2000hsh.googlegroups.com>
Does Lisp provide any means of throwing control deep from a nested
series of IFs? Like this.

(if P
    (if Q R (go here))
    here
    S)

meaning

'if P is true then
   if Q is true then
      evaluate R
      else Jump to procedure here

procedure here

evaluate S' .

I know Lisp's if will not support > 3 arguments.

I also know Lisp has a goto (GO) but I'm not certain if it supports
this usage.

Mark

From: jayessay
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <m3vecwtd6f.fsf@sirius.goldenthreadtech.com>
Mark Tarver <··········@ukonline.co.uk> writes:

> I also know Lisp has a goto (GO) but I'm not certain if it supports
> this usage.

Yes, have a look at tagbody.  Tags have lexical scope and dynamic
extent and will work just fine for what you are talking about here.
Presumably this is some code generation, via a macro.  It's not
something that likely makes sense as "user code".


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Mark Tarver
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <1183828256.162109.176090@r34g2000hsd.googlegroups.com>
On 7 Jul, 17:02, jayessay <······@foo.com> wrote:
> Mark Tarver <··········@ukonline.co.uk> writes:
> > I also know Lisp has a goto (GO) but I'm not certain if it supports
> > this usage.
>
> Yes, have a look at tagbody.  Tags have lexical scope and dynamic
> extent and will work just fine for what you are talking about here.
> Presumably this is some code generation, via a macro.  It's not
> something that likely makes sense as "user code".
>
> /Jon
>
> --
> 'j' - a n t h o n y at romeo/charley/november com

Yes, absolutely - its machine generated code.  You wouldn't want to
write this stuff and nobody except assembly hackers write like this.

I've looked at tagbody; it seems an attenuated version of PROG. Just
executes a series of instructions with optional gotos.  Not certain
that it can return anything.

I tried using PROG.

(SETQ P NIL)
(SETQ Q NIL)
(SETQ S 0)

(DEFUN foo ()
  (PROG ()
   (RETURN
     (COND (P (IF Q R (GO here)))
         here
         S))))

does not work

It seems that tags have to be at the toplevel so the syntax is
............

(PROG Vars
   .....
   Tag
   ....)

So this does work

(DEFUN foo ()
  (PROG ()
   (COND (P (IF Q R (GO here))))
   here
   (RETURN S)))

However in the general case this means pulling out tags from
deeply embedded conditionals and radically changing the code
structure.  So its not an obvious candidate solution.

Mark
From: jayessay
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <m3ir8wt5r0.fsf@sirius.goldenthreadtech.com>
Mark Tarver <··········@ukonline.co.uk> writes:

> I've looked at tagbody; it seems an attenuated version of PROG. Just

prog(*) are macros, almost certainly implemented (in whatever
implementation) via tagbody (which is a special operator).

prog is just (let (..) (block nil ...(tagbody ...))) and prog* (let*
(..) (block nil (tagbody ...))).  The blocks are there because prog(*)
is specified as permitting return.

If you want a bit more control or don't need the bindings or ..., go
straight to tagbody.

> Not certain that it can return anything.

Again, see http://www.lispworks.com/documentation/HyperSpec/Body/s_tagbod.htm

It's explicitly specified to return nil.


> I tried using PROG.
> 
> (SETQ P NIL)
> (SETQ Q NIL)
> (SETQ S 0)
> 
> (DEFUN foo ()
>   (PROG ()
>    (RETURN
>      (COND (P (IF Q R (GO here)))
>          here
>          S))))
> 
> does not work

Of course - that's because you've given an illegal COND clause!  You
can't just have a symbol hanging in the breeze!


> It seems that tags have to be at the toplevel so the syntax is

No, they can be inside nested tagbodies or whatever, and inner tags
of the same name shadow outer tags with that name.

> So this does work
> 
> (DEFUN foo ()
>   (PROG ()
>    (COND (P (IF Q R (GO here))))
>    here
>    (RETURN S)))

That's because you no longer have a bogus COND clause.  If you need
finer control than cond just go directly to if - it's after all it's
machine generated and the cond turns into this anyway (well most
likely it does).

> However in the general case this means pulling out tags from
> deeply embedded conditionals and radically changing the code
> structure.  So its not an obvious candidate solution.

No, your getting all confused here - have a look at the spec for
tagbody and try again.  For example:

(let ((p t)
      (q nil)
      (s 0))
  (block nil
    (tagbody
     start
     (if p
	 (if q r
	   (cond
	    ((= s 0)
	     (go here))
	    (t (go there)))))
     here
     (format t "~%S = ~A" s)
     (setf s 1)
     (go start)
     there
     (return :there))))
=>
S = 0
:THERE


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Mark Tarver
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <1183838681.621547.115920@g4g2000hsf.googlegroups.com>
On 7 Jul, 19:42, jayessay <······@foo.com> wrote:
> Mark Tarver <··········@ukonline.co.uk> writes:
> > I've looked at tagbody; it seems an attenuated version of PROG. Just
>
> prog(*) are macros, almost certainly implemented (in whatever
> implementation) via tagbody (which is a special operator).
>
> prog is just (let (..) (block nil ...(tagbody ...))) and prog* (let*
> (..) (block nil (tagbody ...))).  The blocks are there because prog(*)
> is specified as permitting return.
>
> If you want a bit more control or don't need the bindings or ..., go
> straight to tagbody.
>
> > Not certain that it can return anything.
>
> Again, seehttp://www.lispworks.com/documentation/HyperSpec/Body/s_tagbod.htm
>
> It's explicitly specified to return nil.
>
> > I tried using PROG.
>
> > (SETQ P NIL)
> > (SETQ Q NIL)
> > (SETQ S 0)
>
> > (DEFUN foo ()
> >   (PROG ()
> >    (RETURN
> >      (COND (P (IF Q R (GO here)))
> >          here
> >          S))))
>
> > does not work
>
> Of course - that's because you've given an illegal COND clause!  You
> can't just have a symbol hanging in the breeze!
>
> > It seems that tags have to be at the toplevel so the syntax is
>
> No, they can be inside nested tagbodies or whatever, and inner tags
> of the same name shadow outer tags with that name.
>
> > So this does work
>
> > (DEFUN foo ()
> >   (PROG ()
> >    (COND (P (IF Q R (GO here))))
> >    here
> >    (RETURN S)))
>
> That's because you no longer have a bogus COND clause.  If you need
> finer control than cond just go directly to if - it's after all it's
> machine generated and the cond turns into this anyway (well most
> likely it does).
>
> > However in the general case this means pulling out tags from
> > deeply embedded conditionals and radically changing the code
> > structure.  So its not an obvious candidate solution.
>
> No, your getting all confused here - have a look at the spec for
> tagbody and try again.  For example:
>
> (let ((p t)
>       (q nil)
>       (s 0))
>   (block nil
>     (tagbody
>      start
>      (if p
>          (if q r
>            (cond
>             ((= s 0)
>              (go here))
>             (t (go there)))))
>      here
>      (format t "~%S = ~A" s)
>      (setf s 1)
>      (go start)
>      there
>      (return :there))))
> =>
> S = 0
> :THERE
>
> /Jon
>
> --
> 'j' - a n t h o n y at romeo/charley/november com

Well its a solution - I've run the tagbody approach on a hunky rewrite
definition of prenex normal form. The result is truly a creature of
the night ;).  Best not viewed by those of sensitive disposition.

Mark
From: jayessay
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <m38x9st0id.fsf@sirius.goldenthreadtech.com>
Mark Tarver <··········@ukonline.co.uk> writes:

> Well its a solution - I've run the tagbody approach on a hunky rewrite
> definition of prenex normal form. The result is truly a creature of
> the night ;).  Best not viewed by those of sensitive disposition.

I hear ya.  But hey, it's generated code.  I have some examples which
really contort things from the original nicely specified declarative
code.  Nearly unrecognizable in that sense.  For me, in these sort
of cases, the primary goal (beyond that it works at all, which should
be a given) is that the result is about as optimized (speed and space)
as you could get if there were a savvy programmer hand coding the
requirements of the declarative code.


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Alex Mizrahi
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <468fa542$0$90264$14726298@news.sunsite.dk>
(message (Hello 'Mark)
(you :wrote  :on '(Sat, 07 Jul 2007 14:24:45 -0000))
(

 MT> (if P
 MT>     (if Q R (go here))
 MT>     here
 MT>     S)

 MT> meaning

 MT> 'if P is true then
 MT>    if Q is true then
 MT>       evaluate R
 MT>       else Jump to procedure here

 MT> procedure here

 MT> evaluate S' .

it is either equivalent to:

(if (and P Q)
    R
    S)

or to (when P (if Q R S))

so, actually, i see no reason for "throwing control".

 MT> I know Lisp's if will not support > 3 arguments.

COND can accept as many arguments as you wish.

 MT> I also know Lisp has a goto (GO) but I'm not certain if it supports
 MT> this usage.

i think it does, but do you really need that?
you can define local procedure via flet or labels, and refer to it. (if your 
logic is too complex to be handled by COND).

tagbody/go is a really weird stuff (in any programming language).

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"scorn") 
From: jayessay
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <m3r6nktd1s.fsf@sirius.goldenthreadtech.com>
"Alex Mizrahi" <········@users.sourceforge.net> writes:

> tagbody/go is a really weird stuff (in any programming language).

Not when you understand that it is there mainly for code generation -
it becomes nearly indispensable in some of those scenarios.  And since
Lisp is heavily about code generation (macros) it is anything but
weird to have this facility.


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Mark Tarver
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <1183826001.204652.33950@c77g2000hse.googlegroups.com>
On 7 Jul, 15:37, "Alex Mizrahi" <········@users.sourceforge.net>
wrote:
> (message (Hello 'Mark)
> (you :wrote  :on '(Sat, 07 Jul 2007 14:24:45 -0000))
> (
>
>  MT> (if P
>  MT>     (if Q R (go here))
>  MT>     here
>  MT>     S)
>
>  MT> meaning
>
>  MT> 'if P is true then
>  MT>    if Q is true then
>  MT>       evaluate R
>  MT>       else Jump to procedure here
>
>  MT> procedure here
>
>  MT> evaluate S' .
>
> it is either equivalent to:
>
> (if (and P Q)
>     R
>     S)
>
> or to (when P (if Q R S))
>
> so, actually, i see no reason for "throwing control".
>
>  MT> I know Lisp's if will not support > 3 arguments.
>
> COND can accept as many arguments as you wish.
>
>  MT> I also know Lisp has a goto (GO) but I'm not certain if it supports
>  MT> this usage.
>
> i think it does, but do you really need that?
> you can define local procedure via flet or labels, and refer to it. (if your
> logic is too complex to be handled by COND).
>
> tagbody/go is a really weird stuff (in any programming language).
>
> )
> (With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
> "scorn")

Yes; I know about cond ;)

I've looked at flet - seems to be syntactic sugar for assigning a
function to a local variable.  Nice sugar though :).

Yes; function calls are clearer than GOTOS but ....

But where does the flet go?  The problem is that the call to 'here'
lies outside the scope of any useful flet.  If flet obeys normal
scoping instead of

(if P
    (if Q R (go here))
    here
    S)

we get

(flet ((here () S))  ;; guessing the syntax here
  (if P
      (if Q R (here))
      (here)))

The question is - is this efficient?  Consider if P and Q are true,
then the computer should return R.  The flet is a waste of time. And
if flet is dynamically evaluating its binding at runtime, it *may* be
inherently slow.  At any rate - fast or slow - it does not seem
efficient in this context.

Another alternative is to hive off 'here' into a global definition.
This gives

(if P
    (if Q R (here))
    (here))

(DEFUN here () S)

Mark
From: Dan Bensen
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <f6ojjc$gka$1@wildfire.prairienet.org>
Mark Tarver wrote:
 > (flet ((here () S))  ;; guessing the syntax here
 >   (if P
 >       (if Q R (here))
 >       (here)))
 > The question is - is this efficient?

If efficiency is important enough to live with ugliness:

(defmacro tagged-if* (test if-true &rest if-falses)
   (let ((true  (gensym))
         (false (gensym))
         (end   (gensym)))
     `(tagbody
       (if ,test (go ,true) (go ,false))
       ,true ,if-true
       (go ,end)
       ,false ,@(append if-falses (list end))
           )))

(defun test (p q)
   (tagged-if* p (if q (write-string " P is true, Q is false. ")
                   (go x))
     (write-string " P is false. ")
     x
     (write-string " Doing S."))
(terpri)
)

(test t t)
(test t nil)
(test nil t)
(test nil nil)

=>
  P is true, Q is false.
  Doing S.
  P is false.  Doing S.
  P is false.  Doing S.

-- 
Dan
www.prairienet.org/~dsb/
From: Dan Bensen
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <f6ok11$gpj$1@wildfire.prairienet.org>
Dan Bensen wrote:
> (defun test (p q)
>   (tagged-if* p (if q (write-string " P is true, Q is false. ")
> (test t t)
> =>
>  P is true, Q is false.

I mean Q is *true*.

-- 
Dan
www.prairienet.org/~dsb/
From: Scott Burson
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <1183867642.128732.253140@z28g2000prd.googlegroups.com>
On Jul 7, 9:33 am, Mark Tarver <··········@ukonline.co.uk> wrote:
> (flet ((here () S))
>   (if P
>       (if Q R (here))
>       (here)))
>
> The question is - is this efficient?

Yes (assuming a good compiler, such as SBCL's).  The `flet' is just a
declaration; no closure allocation is necessary since the procedure
does not escape the context (it's not returned or stored in the heap).

I highly recommend reading the early Scheme literature, particularly
the "lambda-the-ultimate" papers, which explain the relationship
between `goto' and function calls, and in particular, why code like
this can be compiled identically to the version with `tagbody' and
`go'.  A lot of these techniques have been incorporated into modern
Common Lisp compilers.

-- Scott
From: Alex Mizrahi
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <4690c6fd$0$90273$14726298@news.sunsite.dk>
(message (Hello 'Mark)
(you :wrote  :on '(Sat, 07 Jul 2007 16:33:21 -0000))
(

 MT> Yes; I know about cond ;)

 MT> I've looked at flet - seems to be syntactic sugar for assigning a
 MT> function to a local variable.  Nice sugar though :).

it's not assignment to a variable, it just tells 'compiler' to associate a 
name with some code.
note that it does not require any actions in run time -- compiler is free to 
inline this code, or implement it just exactly as GOTO, whatever it likes.

 MT> we get

 MT> (flet ((here () S))  ;; guessing the syntax here
 MT>   (if P
 MT>       (if Q R (here))
 MT>       (here)))

why not (if (and P Q) R (here)) ?

 MT> The question is - is this efficient?

yes.

 MT>   Consider if P and Q are true, then the computer should return R.  The
 MT> flet is a waste of time.
 MT>  And if flet is dynamically evaluating its binding at runtime, it *may*
 MT> be inherently slow.  At any rate - fast or slow - it does not seem
 MT> efficient in this context.

modern Lisps doesn't work evaluating operators one at time. (in fact, that 
would be tricky with lexical bindings).
compiler can optimize code whatever it wants, so it doesn't need to execute 
anything at run-time.

you can try yourself converting FLET to TAGBODY/GO via a macro (at least 
simple cases), why do you think compiler writers are not able to do this?

by the way, even if you write LAMBDA in function's coce, it also can be 
compiled, so it doesn't require any actions in real-time to create that 
LAMBDA (unless it's a closure, but even in this case actions are minimal).

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"scorn") 
From: Matthias Buelow
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <5fa2f8F3b6ssgU1@mid.dfncis.de>
Mark Tarver wrote:

> Does Lisp provide any means of throwing control deep from a nested
> series of IFs? Like this.
> 
> (if P
>     (if Q R (go here))
>     here
>     S)

Here's another way (instead of tagbody):

(if t
  (progn
    (block nil
      (if nil 1 (progn
                  (return)
                  (princ "won't see this!"))))
    'here)
  'there)

You can also name the block (instead of nil) and use return-from.
From: Matthias Buelow
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <5fa2luF3b6ssgU2@mid.dfncis.de>
I wrote:

> Here's another way (instead of tagbody):
...

and another one, since I just remembered that block does an implicit
progn, which is probably clearer:

(if t
  (progn
    (if nil 1 (block nil
                 (princ "booh!")
                 (return)
                 (princ "won't see this!")))
    'here)
  'there)
From: Tim Bradshaw
Subject: Re: throwing control within a nested conditional
Date: 
Message-ID: <1183902149.567712.69600@g4g2000hsf.googlegroups.com>
On Jul 7, 3:24 pm, Mark Tarver <··········@ukonline.co.uk> wrote:
> Does Lisp provide any means of throwing control deep from a nested
> series of IFs? Like this.
>
Yes, many such.  In fact the main problem is knowing which one to
use.  I prefer BLOCK & RETURN-FROM as it seems to me clearest:

(block done
  ....
    ... (return-from done value)
    ...
  ....)

This has lexical scope which is generally what you want, and I find
its meaning very clear (where GO, say, would not be).

--tim