From: Zachary Turner
Subject: Can lisp functions have more than one point of return?
Date: 
Message-ID: <livp8.55592$J53.1971853@typhoon.austin.rr.com>
I'm new to LISP and I'm wondering if there is any way to make a LISP
function return from multiple locations within the functions?  Or does it
always simply return the result of the last statement in the function?
Consider the following basic function:

(defun basic-function()
    (if (> 4 0)
        nil)
    (if (> 4 0)
        t))

This function will return t.  I would like it to return nil however.
Clearly I can rewrite the function as:

(defun basic-function()
    (if (> 4 0)
        nil
      (if (> 4 0)
          t)))

but now I've added a seemingly unnecessary level of nesting.  The reason I
ask about this is because it seems like there may be cases where you may
want to do some complex parameter validation and immediately return if the
parameters fail to be validated.  Without multiple points of return I think
you will be forced to either write a function to do your validation and
simply call that function (not a big deal, I admit), or have many many
levels of nesting before you ever get to the meat of the function.

Obviously there are many other reasons besides just parameter validation
where multiple points of return would be useful, but this is the one that
led me to ask the question.  If it is the case that LISP does not allow
this, would somebody mind explaining the motivation behind this?  It must
have some advantages which I am not aware of.

Thanks very much
Zachary Turner

From: Jon Allen Boone
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <m3it7dz78b.fsf@validus.delamancha.org>
Zachary,

You wrote:

> I'm new to LISP

  welcome..

> Or does it always simply return the result of the last statement in the
> function?

  I think you want to look at (cond ...)

> Clearly I can rewrite the function as:
>
> (defun basic-function()
>     (if (> 4 0)
>         nil
>       (if (> 4 0)
>           t)))
>
> but now I've added a seemingly unnecessary level of nesting.

(defun basic-function (x)
 "This is a basic function that uses (cond ...)."
  (cond ((> x 0) nil)
        ((< x 0)
          (format t "x: ~S~%" x)
          t)))


-jon
-- 
------------------
Jon Allen Boone
········@delamancha.org
From: Christopher C. Stacy
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <uhemxf8v5.fsf@theworld.com>
>>>>> On Sun, 31 Mar 2002 03:22:57 GMT, Zachary Turner ("Zachary") writes:
 Zachary> I'm new to LISP and I'm wondering if there is any way to make a LISP
 Zachary> function return from multiple locations within the functions?

 Zachary> (defun basic-function()
 Zachary>     (if (> 4 0)
 Zachary>         nil
 Zachary>       (if (> 4 0)
 Zachary>           t)))

 Zachary> but now I've added a seemingly unnecessary level of nesting.

You could simplify the above as follows:

(defun basic-function ()
  (> 4 0))

which will always return NIL.

Lisp does allow you to return from arbitrary points in the function,
by calling RETURN and especially RETURN-FROM.  But doing that is a
little bit unusual: normally you would return the last value as you
are doing above.  Your example code above is the normal and tasteful
way to do what you want, but you're right about the extra nesting.  
So you were on the right track, before you started looking for an
unusual way to exit the function.  

Before we go any further, though, first let's change the example
around to take an argument X so that we can have a more useful
function to play with.

Here's a simple way to write it:

(defun basic-function (x)
  (> x 4))              ;Return T if X is more than 4, else return NIL.

Now let's have it do something useful in two branches:

(defun basic-function (x)
  (if (> x 4)
      nil
      (if (< x 10)
          nil)))

So BASIC-FUNCTION and checks to see whether X is between 4 and 10,
noninclusive.  But it will still always return NIL for all X,
because if there is no "else" clause for an IF, that's NIL.

(defun basic-function (x)
  (if (> x 4)                   ;If X is more than 4
      nil                       ; return NIL
      (if (< x 10)              ;Else if X is less than 10
          nil)))                ; return NIL
                                ;Else return NIL.


A more interesting function would return T, instead:

(defun basic-function (x)
  (if (> x 4)                   ;If X is more than 4
      t                         ; return T
      (if (< x 10)              ;Else if X is less than 10
          t)))                  ; return T
                                ;Else return NIL.

Of course, the bug here is that the function will return T
if X is *either* more than 4 *or* less than 10.
That's kind of a silly thing to write, but at least we're
back to your original question about the excess nesting.

When you have several conditionals that you want to test consecutively
until one of them succeeds, rather than nesting IFs you should consider
using COND.  The following function does the same thing as the code above:

(defun basic-function (x)
  (cond ((> x 4) t)
        ((< x 10) t)))

Of course, that returns T for any number that's greater than 4,
since all numbers below 4 are also below 10.

Here's a function that returns T for all negative numbers, 
and for positive numbers more than 4.

(defun basic-function (x)
  (cond ((> x 4) t)
        ((< x 0) t)))

In this example, the only thing we're doing in the "then" part of the
COND clauses is returning the value T.  You can put as many expressions
there as you want.  Here's a function that increases positive numbers
that are larger than 4 by an order of magnitude, but just returns the
number X if it's negative.  Note that either of those results would be
considered "true" values in Lisp.  Otherwise the function will return 
NIL, which is the "false" value.

(defun basic-function (x)
  (cond ((> x 4) 
         (format t "~&Accentuate the (sufficiently) positive...")
         (* 10 x))
        ((< x 0)
         (format t "~&Don't mess with Mister In-Between.")
         x)))

By the way, there are other control forms in Lisp besides the family
of IF, COND, WHEN, and UNLESS.   You can also use AND, OR, and NOT,
as in the following example:

(defun basic-function (x)
  (or (> x 4)
      (minusp x)))

That function returns T if the conditions are met, else NIL.

Hope these examples help!
From: Joe Marshall
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <RQvp8.45098$44.17977216@typhoon.ne.ipsvc.net>
You can use RETURN or RETURN-FROM

(defun basic-function ()
    (when (> 4 0) (return t))
     ....)

Another idiom that is handy is using AND.
AND executes the subforms in turn and returns
NIL as soon as any subform returns NIL.  If none
of them return NIL, then the value of the last
subform is returned.

(defun foo (x)
   (and (satisfies-condition-1 x)
        (satisfies-condition-2 x)
        (compute-something x)))

This will return NIL if x doesn't satisfy the
conditions, but will call compute-something if it
does.

If you are doing parameter validation, consider
CHECK-TYPE.

(defun foo (x)
  (check-type x (integer 3 8))
   ....)

Not only will this barf if x is not in [3,8], but
it will enter the error handler and allow you to
fix it and proceed.


> If it is the case that LISP does not allow
> this, would somebody mind explaining the motivation behind this?  It must
> have some advantages which I am not aware of.

Lisp allows just about anything you can come up with.
On the other hand, there might be good reason for not
using a non-local exit.  It might not be immediately
obvious that control could `jump out'.

(progn
     (validate-something)
     (really hairy calculation
        ( many levels deep
            (.....)))
     (print "Hey, it's done!"))

If you didn't spot the RETURN statement buried in the
hairy code, you might be surprised to find that function
returned without printing anything.
From: Takehiko Abe
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <keke-0204021124420001@solg4.keke.org>
"Joe Marshall" wrote:

> You can use RETURN or RETURN-FROM
>
> 
> (defun basic-function ()
>     (when (> 4 0) (return t))
>      ....)

RETURN requires block nil.

-- 
"What we hear constantly is that after September 11th, everything changed.
There is a good rule of thumb: if something is repeated over and over as
obvious, the chances are that it is obviously false."       -- Chomsky
<http://www.zmag.org/content/ForeignPolicy/chomsky_march26.cfm>
From: Takehiko Abe
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <keke-3103021350230001@solg4.keke.org>
In article <·······················@typhoon.austin.rr.com>, 
"Zachary Turner" <·······@bindview.com> wrote:

> I'm new to LISP and I'm wondering if there is any way to make a LISP
> function return from multiple locations within the functions?

check RETURN-FROM special form.

> 
> (defun basic-function()
>     (if (> 4 0)
>         nil)
>     (if (> 4 0)
>         t))

(defun basic-function (n)
  (when (> n 0)
     (return-from basic-function nil))
  ...
  ...)

-- 
"What we hear constantly is that after September 11th, everything changed.
There is a good rule of thumb: if something is repeated over and over as
obvious, the chances are that it is obviously false."       -- Chomsky
<http://www.zmag.org/content/ForeignPolicy/chomsky_march26.cfm>
From: Erik Naggum
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <3226539899126540@naggum.net>
* "Zachary Turner" <·······@bindview.com>

  See the index entry on "return" in the HyperSpec.  If you do not have
  access to the HyperSpec, you cannot learn Common Lisp well.  Kent Pitman,
  the editor of the standard graciously made it all available on the Web,
  and you can (and should) download your own copy to install locally.
  Several Emacs Lisp interfaces to it exist, among them mine, which I have
  not updated since the online version moved and changed randmoly, so
  search the Xanalys web site.  Others have made some changes to my
  hyperspec.el that loads its symbol->page association from a file that
  Xanalys seems to have added to hide their overly short filenames.  Franz
  Inc also has a version of the standard from what I believe are the same
  sources, and which they ship with every release.  The online address is
  http://franz.com/support/documentation/6.1/ansicl/ansicl.htm

///
-- 
  In a fight against something, the fight has value, victory has none.
  In a fight for something, the fight is a loss, victory merely relief.
From: Paolo Amoroso
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <=zmnPG4aAKyVYLt2QZD5zwwKMBSF@4ax.com>
On Sun, 31 Mar 2002 05:04:43 GMT, Erik Naggum <····@naggum.net> wrote:

[about the HyperSpec]
>   Several Emacs Lisp interfaces to it exist, among them mine, which I have
>   not updated since the online version moved and changed randmoly, so
>   search the Xanalys web site.  Others have made some changes to my
>   hyperspec.el that loads its symbol->page association from a file that
>   Xanalys seems to have added to hide their overly short filenames.  Franz

That modified version is included with ILISP. By the way, CLISP has been
providing HyperSpec access via EXT:CLHS for the last couple of versions.


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://www.paoloamoroso.it/ency/README
[http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/]
From: Zachary Turner
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <11Jp8.105423$Vl.3617235@typhoon.austin.rr.com>
"Erik Naggum" <····@naggum.net> wrote in message
·····················@naggum.net...
> * "Zachary Turner" <·······@bindview.com>
>
>   See the index entry on "return" in the HyperSpec.  If you do not have
>   access to the HyperSpec, you cannot learn Common Lisp well.  Kent
Pitman,
>   the editor of the standard graciously made it all available on the Web,
>   and you can (and should) download your own copy to install locally.
>   Several Emacs Lisp interfaces to it exist, among them mine, which I have
>   not updated since the online version moved and changed randmoly, so
>   search the Xanalys web site.  Others have made some changes to my
>   hyperspec.el that loads its symbol->page association from a file that
>   Xanalys seems to have added to hide their overly short filenames.  Franz
>   Inc also has a version of the standard from what I believe are the same
>   sources, and which they ship with every release.  The online address is
>   http://franz.com/support/documentation/6.1/ansicl/ansicl.htm
>
> ///
> --
>   In a fight against something, the fight has value, victory has none.
>   In a fight for something, the fight is a loss, victory merely relief.

Thanks for the link, looks like the HyperSpec will come in handy.  My
question now is how natural is it to use return?  One poster mentioned it is
a bit unusual to use return and then a few people mentioned cond being the
generally accepted way to test multiple conditions and that in the case of
parameter validation cond would be a good choice.  So I'm wondering overall
how much is return actually used?

Thanks
From: Coby Beck
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <hpKp8.246747$kb.13931088@news1.calgary.shaw.ca>
"Zachary Turner" <·······@bindview.com> wrote in message
····························@typhoon.austin.rr.com...
> Thanks for the link, looks like the HyperSpec will come in handy.  My
> question now is how natural is it to use return?  One poster mentioned it
is
> a bit unusual to use return and then a few people mentioned cond being the
> generally accepted way to test multiple conditions and that in the case of
> parameter validation cond would be a good choice.  So I'm wondering
overall
> how much is return actually used?

In terms of parameter validation, another common idiom would be to throw an
exception.

(defun foo (arg)
    (when (whacky? arg)
        (error 'whacky-args :arg arg :problem "it's whacky"))
    (normal code here ....))

If you don't want that and a nil returned is what callers expect as
exceptional then return-from seems appropriate though it is definately
simply a matter of style:

(defun foo (arg)
    (when (sane arg)   ;; same as (unless (not (whacky? arg))..)
        (normal code here ...)))
vs.
(defun foo (arg)
    (when (whacky? arg)
        (return-from foo nil))
    (normal code here...))

I would use the latter if the depth of nesting started to interfere with
readability and to emphasis the exceptional nature of a whacky arg.  People
have differing opinions on whether it is proper to use WHEN and UNLESS for
the return values.

--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Erik Naggum
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <3226610746933462@naggum.net>
* Zachary Turner
| My question now is how natural is it to use return?

  Well, there are a few hints.  Many forms set up a block named nil from
  which you can return with a simple return instead of return-from.  This
  is particularly prevalent for the iteration constructs do, do*, dolist,
  and loop, so you can break out of a loop early.  This is much cleaner
  than using an extra variable of heavier mechanisms locally.

| So I'm wondering overall how much is return actually used?

  I think you should worry about this later and focus on learning the
  language and finding uses of the constructs you learn.  Knowing when to
  use a construct is knowledge.  Knowing when not to use a construct is
  wisdom.  If you merely collect knowledge without much understanding, you
  will at least be skillful.  If you merely collect wisdom without much
  understanding, you will only be immobilized.

///
-- 
  In a fight against something, the fight has value, victory has none.
  In a fight for something, the fight is a loss, victory merely relief.
From: Steve Long
Subject: Re: Can lisp functions have more than one point of return?
Date: 
Message-ID: <3CA89F11.6F5D88D7@hotmail.com>
Zachary Turner wrote:

> I'm new to LISP

Yes...

> This function will return t.  I would like it to return nil however.
> Clearly I can rewrite the function as:
>
> (defun basic-function()
>     (if (> 4 0)
>         nil
>       (if (> 4 0)
>           t)))
>
> but now I've added a seemingly unnecessary level of nesting.

Not really. This is generally the way things are done in Lisp.

> you may want to do some complex parameter validation and immediately return
> if the
> parameters fail to be validated.  Without multiple points of return I think
> you will be forced to either write a function to do your validation and
> simply call that function

The main problem is that you are thinking like a C or Java programmer and
using a language that frees you from curly braces. You can handle the
multi-case scenario just like you' ve stated using Lisp functions, macros and
special forms, and even pop out of your function with things like ERROR and
RETURN.


sal