From: Tamas Papp
Subject: looking for appropriate control idiom
Date: 
Message-ID: <87lkclkuky.fsf@pu100877.student.princeton.edu>
Depending on circumstances, sometimes I need to perform a
transformation on a pair of numbers, returned as values, but sometimes
not.  Then I need to keep using either the transformed pair or the
original pair.  Example code of what I am doing now follows, I would
like to know

1) if this is the way of doing it, because then I would make it into a
macro

2) or if there is something saner.

(defun foo (x y)
  ;; in real life, performs an operation which only makes sense for x
  ;; and y as a pair
  (values (1+ x) (1- y)))

(defun bar (x1 y1 x2 y2 &optional (do-foo))
  (multiple-value-bind (x1 y1) (if do-foo
				   (foo x1 y1)
				   (values x1 y1))
    (multiple-value-bind (x2 y2) (if do-foo
				     (foo x2 y2)
				     (values x2 y2))
      ;; in real life, here follow 10 lines of code using x1, y1, x2,
      ;; y2, will do with something trivial here for the sake of example
      (+ x1 y1 x2 y2))))

Thanks,

Tamas

From: Tobias C. Rittweiler
Subject: Re: looking for appropriate control idiom
Date: 
Message-ID: <873aytul40.fsf@freebits.de>
Tamas Papp <······@gmail.com> writes:

> Depending on circumstances, sometimes I need to perform a
> transformation on a pair of numbers, returned as values, but sometimes
> not.  Then I need to keep using either the transformed pair or the
> original pair.  Example code of what I am doing now follows, I would
> like to know
>
> 1) if this is the way of doing it, because then I would make it into a
> macro
>
> 2) or if there is something saner.


> (defun bar (x1 y1 x2 y2 &optional (do-foo))
>   (multiple-value-bind (x1 y1) (if do-foo
> 				   (foo x1 y1)
> 				   (values x1 y1))
>     (multiple-value-bind (x2 y2) (if do-foo
> 				     (foo x2 y2)
> 				     (values x2 y2))
>       ;; in real life, here follow 10 lines of code using x1, y1, x2,
>       ;; y2, will do with something trivial here for the sake of example
>       (+ x1 y1 x2 y2))))


(defun bar (x1 y1 x2 y2 &optional do-foo)
  (flet ((maybe-foo x y)
           (if do-foo (foo x y) (values x y)))
    (multiple-value-bind (x1 y1) (maybe-foo x1 y1)
      (multiple-value-bind (x2 y2) (maybe-foo x2 y2)
         ...))))

For the case that you want this to be abstracted out, because it's
needed on several places in your code, you could do it for example like
this:

  (defun maybecall (cond fn &rest args)
    (apply (if cond fn #'values) args)) 

  (defun bar (x1 y1 x2 y2 &optional do-foo)
    (multiple-value-bind (x1 y1) (maybecall do-foo #'foo x1 y1)
      (multiple-value-bind (x2 y2) (maybecall do-foo #'foo x2 y2)
         ...)))

If you don't want the multiple MULTIPLE-VALUE-BINDs, you may be
interested in something like [1]. Also you may want to consider
introducing a data structure for coordination pairs via DEFSTRUCT, and
then make your functions take and return those pairs. This could also
help with float unboxing and would make it:

  (defun bar (coords1 coords2 &optional do-foo)
    (let ((coords1 (if do-foo (foo coords1) coords1))
          (coords2 (if do-foo (foo coords2) coords2)))
      (with-accessors ((x1 x-coord) (y1 y-coord)) coords1
        (with-accessors ((x2 x-coord) (y2 y-coord)) coords2
           ...))))

(With the possibility to introduce a macro WITH-COORDINATES.)

HTH,

  -T.

[1] http://www.cliki.net/bind
From: Thomas A. Russ
Subject: Re: looking for appropriate control idiom
Date: 
Message-ID: <ymitzr84a3q.fsf@blackcat.isi.edu>
Tamas Papp <······@gmail.com> writes:

> (defun bar (x1 y1 x2 y2 &optional (do-foo))
>   (multiple-value-bind (x1 y1) (if do-foo
> 				   (foo x1 y1)
> 				   (values x1 y1))
>     (multiple-value-bind (x2 y2) (if do-foo
> 				     (foo x2 y2)
> 				     (values x2 y2))
>       ;; in real life, here follow 10 lines of code using x1, y1, x2,
>       ;; y2, will do with something trivial here for the sake of example
>       (+ x1 y1 x2 y2))))

Clearer to me would be using MULTIPLE-VALUE-SETQ
 or Alan Crowe's SETF (VALUES ...) ...) construct:

 (defun bar (x1 y1 x2 y2 &optional (do-foo))
   (when do-foo
     (multiple-value-setq (x1 y1) (foo x1 y1))
     (multiple-value-setq (x2 y2) (foo x2 y2)))

   ;; in real life, here follow 10 lines of code using x1, y1, x2,
   ;; y2, will do with something trivial here for the sake of example
   (+ x1 y1 x2 y2))


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Scott Burson
Subject: Re: looking for appropriate control idiom
Date: 
Message-ID: <1186679886.833227.211390@g12g2000prg.googlegroups.com>
On Aug 9, 12:58 am, Tamas Papp <······@gmail.com> wrote:
(defun bar (x1 y1 x2 y2 &optional (do-foo))
>   (multiple-value-bind (x1 y1) (if do-foo
>                                    (foo x1 y1)
>                                    (values x1 y1))
>     (multiple-value-bind (x2 y2) (if do-foo
>                                      (foo x2 y2)
>                                      (values x2 y2))
>       ;; in real life, here follow 10 lines of code using x1, y1, x2,
>       ;; y2, will do with something trivial here for the sake of example
>       (+ x1 y1 x2 y2))))
>

I'm rather fond of this idiom, actually, except that `multiple-value-
bind' is too long.  Let me take the opportunity to plug my extended
`let' macro, with which you could say

  (let ((x1 y1 (if do-foo (foo x1 y1) (values x1 y1)))
        (x2 y2 (if do-foo (foo x2 y2) (values x2 y2))))
    ...)

This version of `let' has another feature -- it allows you to specify
any combination of parallel and sequential binding, thus generalizing
`let' and `let*'.  Sequentiality is expressed by nesting, e.g.:

  (let ((x (foo))
        ((y (bar x))))
    ...)

All clauses at a given nesting level are evaluated in a scope that
includes the bindings of all clauses at all shallower levels.

This macro is in my Misc-Extensions package which is ASDF-Installable,
or see http://common-lisp.net/project/misc-extensions/

-- Scott
From: Alan Crowe
Subject: Re: looking for appropriate control idiom
Date: 
Message-ID: <86r6mc8rrn.fsf@cawtech.freeserve.co.uk>
Tamas Papp <······@gmail.com> writes:

> Depending on circumstances, sometimes I need to perform a
> transformation on a pair of numbers, returned as values, but sometimes
> not.  Then I need to keep using either the transformed pair or the
> original pair.  Example code of what I am doing now follows, I would
> like to know
> 
> 1) if this is the way of doing it, because then I would make it into a
> macro
> 
> 2) or if there is something saner.
> 
> (defun foo (x y)
>   ;; in real life, performs an operation which only makes sense for x
>   ;; and y as a pair
>   (values (1+ x) (1- y)))
> 
> (defun bar (x1 y1 x2 y2 &optional (do-foo))
>   (multiple-value-bind (x1 y1) (if do-foo
> 				   (foo x1 y1)
> 				   (values x1 y1))
>     (multiple-value-bind (x2 y2) (if do-foo
> 				     (foo x2 y2)
> 				     (values x2 y2))
>       ;; in real life, here follow 10 lines of code using x1, y1, x2,
>       ;; y2, will do with something trivial here for the sake of example
>       (+ x1 y1 x2 y2))))
> 

I think the issue is that you already have bindings of x1,
y1, x2, y2 set up on entry to the routine so it seems clumsy
to be creating more. The natural thing to do is to overwrite
them with the result of foo when foo is needed, but foo
returns multiple values. 

There is no problem see

5.1.2.3 VALUES Forms as Places

For example

CL-USER> (defun foo (x y)
           (values (* 10 x) (* 10 y)))
FOO

CL-USER> (let ((x 3)(y 5))
           (if (y-or-n-p "foo? ")
               (setf (values x y) (foo x y)))
           (list x y))
foo? y

(30 50)

CL-USER> (let ((x 3)(y 5))
           (if (y-or-n-p "foo? ")
               (setf (values x y) (foo x y)))
           (list x y))
foo? n

(3 5)

Alan Crowe
Edinburgh
Scotland