From: Harag
Subject: The lesser evil?
Date: 
Message-ID: <brbtdk$koq$1@ctb-nnrp2.saix.net>
Looking at some code I have produced and reading paul graham again I have
been trying to 'clean' up my act and get more functional but I end up with
some questions.

I find this patern a lot in my code

(defun non-functional? (x)
  (let ((b 0) (c 0))
    (if (not (equal x nil))
        (progn
          (setf b (+ x 1))
          (setf c (- x 1))))
    (list b c)))

vs

My first try at making it functional repeats the if...yuk

(defun functional? (x)
  (list (if (not (equal x nil))
            (+ x 1))
        (if (not (equal x nil))
            (- x 1))))

vs

(defun funcational? (x)
  (if x
      (list (1+ x) (1- x))
    (list nil nil)))

The guys on #Lisp came up with this last version which looks beautiful and
clean but I find myself thinking that repeating code to do the same 'thing'
but only in different places in the same function or program for that matter
is as 'bad' if not worse than using the imperical version of the function.

I must add that this would most likely only be a problem if the code was a
little more complicated than (list a b) and  I suppose at such a time the
piece of code can most probabily be stuffed into a function solving the
problem?

Just wondering aloud again.

From: Timothy Moore
Subject: Re: The lesser evil?
Date: 
Message-ID: <wdrad5yv2g1.fsf@trousse.labri.fr>
"Harag" <·········@psychedelic.co.za> writes:

> (defun funcational? (x)
>   (if x
>       (list (1+ x) (1- x))
>     (list nil nil)))
> 
> The guys on #Lisp came up with this last version which looks beautiful and
> clean but I find myself thinking that repeating code to do the same 'thing'
> but only in different places in the same function or program for that matter
> is as 'bad' if not worse than using the imperical version of the function.
> 
Your first example had a different result, producing a list of 0s if x
is nil. Anyway, that style is fine; sometimes you need to repeat
yourself. But I use multiple-value-bind when I need to bind more than
one variable based on a single test:

(defun functional? (x)
  (multiple-value-bind (b c)
      (if x
	  (values (1+ x) (1- x))
	  (values nil nil))
    (list b c)))

If the repetition of the VALUES bothers you, you can rely on the
default behavior for multiple-value-bind, but I think that can be
confusing:

(defun functional? (x)
  (multiple-value-bind (b c)
      (when x
	  (values (1+ x) (1- x)))
    (list b c)))

Tim
From: Drew McDermott
Subject: Re: The lesser evil?
Date: 
Message-ID: <brcjkc$gfq$1@news.wss.yale.edu>
Timothy Moore wrote:
> I use multiple-value-bind when I need to bind more than
> one variable based on a single test:
> 
> (defun functional? (x)
>   (multiple-value-bind (b c)
>       (if x
> 	  (values (1+ x) (1- x))
> 	  (values nil nil))
>     (list b c)))
> 
> If the repetition of the VALUES bothers you, you can rely on the
> default behavior for multiple-value-bind, but I think that can be
> confusing:
> 
> (defun functional? (x)
>   (multiple-value-bind (b c)
>       (when x
> 	  (values (1+ x) (1- x)))
>     (list b c)))
> 
> Tim

Ugh.  There is no reason in the world why the repetition of 'values' 
should bother anyone.  It's not like it's a function that's expensive to 
call.  It's not a function at all, and the compiler will just treat it 
as a directive concerning which way to send the computed values.  The 
result will probably be the same as for the less pretty version with 
'setq's.

-- 
                                    -- Drew McDermott
                                       Yale Computer Science Department
From: Kalle Olavi Niemitalo
Subject: Re: The lesser evil?
Date: 
Message-ID: <87smjp82yo.fsf@Astalo.kon.iki.fi>
Drew McDermott <··················@at.yale.dot.edu> writes:

> It's not a function at all,

(values-list list) == (apply #'values list)

You couldn't do that if VALUES weren't a function.

> and the compiler will just treat it as a directive concerning
> which way to send the computed values.

The compiler is free to inline the call, just like with CAR or EQ.
From: Kent M Pitman
Subject: Re: The lesser evil?
Date: 
Message-ID: <sfwoeucu2oz.fsf@shell01.TheWorld.com>
Kalle Olavi Niemitalo <···@iki.fi> writes:

> Drew McDermott <··················@at.yale.dot.edu> writes:
> 
> > It's not a function at all,
> 
> (values-list list) == (apply #'values list)
> 
> You couldn't do that if VALUES weren't a function.

I don't think he meant it in that sense. 

I think he meant it like if one said 'NOT is not a function.'

Doing

 (if (not x) y z)

is not slowe rthan

 (if x z y)

because (in some sense) NOT is not [always] a function, but is a way 
in some contexts of simply directing raw data flow.  The compiler knows
this and does not issue function calls.  That it is implemented as a 
function and that there are other compositional effects of implementing
it as a function is important, but is irrelevant to what I took to be
Drew's essential point ... with which I agreed, btw.
 
> > and the compiler will just treat it as a directive concerning
> > which way to send the computed values.
> 
> The compiler is free to inline the call, just like with CAR or EQ.

Absolutely, but some calls when inlined actually "create code" while
others only "reshape it", and I think Drew was just trying to grab at
terminology for expressing this subtle difference.  Given that we, the
langauge designers, did not provide terminology for expressing this
difference in a canonical way, I personally think it's worth defending
the fact that he had to bumble around with makeshift wording.  One of
the reasons I insisted there be as much glossary as there was in ANSI CL
was exactly because there's a huge amount of descriptive terminology we
all share to describe the language, and yet even for all that, there are
tons of other concepts we share that are not listed there and for which
we must clumsily resort to already-overloaded and ill-defined English.
(I say ill-defined not only in the sense of having no meaning, btw, which
is sometimes the case, but also in the sense of not having an articulated
meaning for the common uses to which words are regularly put within our
jargon-laiden community.)
From: Kenny Tilton
Subject: Re: The lesser evil?
Date: 
Message-ID: <3zgCb.399368$pT1.102426@twister.nyc.rr.com>
Harag wrote:

> Looking at some code I have produced and reading paul graham again I have
> been trying to 'clean' up my act and get more functional but I end up with
> some questions.
> 
> I find this patern a lot in my code
> 
> (defun non-functional? (x)
>   (let ((b 0) (c 0))
>     (if (not (equal x nil))
>         (progn
>           (setf b (+ x 1))
>           (setf c (- x 1))))
>     (list b c)))
> 
> vs
> 
> My first try at making it functional repeats the if...yuk
> 
> (defun functional? (x)
>   (list (if (not (equal x nil))
>             (+ x 1))
>         (if (not (equal x nil))
>             (- x 1))))

Agreed, yuk. The conditional should not be repeated as long that really 
is one conditional deciding two values (not two values which just happen 
to be decided by the same conditional, which could change after later 
analysis.

btw. that could also be

   (list (when x (1+ x)) (when x (1- x)))

> 
> vs
> 
> (defun funcational? (x)
>   (if x
>       (list (1+ x) (1- x))
>     (list nil nil)))
> 
> The guys on #Lisp came up with this last version which looks beautiful and
> clean but I find myself thinking that repeating code to do the same 'thing'
> but only in different places in the same function or program for that matter
> is as 'bad' if not worse than using the imperical version of the function.

Are you sure this would not work?:

    (when x
       (list (1+ x) (1- x)))

ie, return nil instead of '(nil nil). Possibly this function is harder 
than it has to be because of problems in the code of its clients.

Mind you, as someone else pointed out, you started with (list 0 0) as 
the output (but then the question is the same: why do you need that?

kt



-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: Pascal Costanza
Subject: Re: The lesser evil?
Date: 
Message-ID: <brc2et$khr$1@newsreader3.netcologne.de>
Harag wrote:

> (defun funcational? (x)
>   (if x
>       (list (1+ x) (1- x))
>     (list nil nil)))

What are you trying to achieve?

The check whether x is not nil doesn't guarantee that the rest of the 
code will execute without error. Without any further information about 
where and how you want to use this code I would rather opt for one of 
the following versions:

(defun f (x)
   (list (1+ x) (1- x)))

or:

(defun f (x)
   (when (numberp x)
     (list (1+ x) (1- x))))

or even:

(defun f (x)
   (assert (numberp x))
   (list (1+ x) (1- x)))

also interesting:

(defmethod f ((x number))
   (list (1+ x) (1- x)))


Producing a list with two nils seems gratuitous to me.


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Marco Baringer
Subject: Re: The lesser evil?
Date: 
Message-ID: <m2vfom13ds.fsf@bese.it>
maybe your trying to re-write the wrong code. If you often need to
return (1- x) if x is a number or 0 if x is nil:

(defun my-minus-1 (x)
  (if (null x)
      0
      (1- x)))

(defun my-plus-1 (x)
  (if (null x)
      0
      (1+ x)))

(defun |is this "functional" now?| (x)
  (list (my-minus-1 x) (my-plus-1 x)))

-- 
-Marco
Ring the bells that still can ring.
Forget your perfect offering.
There is a crack in everything.
That's how the light gets in.
     -Leonard Cohen