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
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
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
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
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
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
(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")
"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
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
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/
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/
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
(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)
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