From: Tamas K Papp
Subject: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <73nahgFvsmfhU1@mid.individual.net>
I write a lot of fractions these days, and I am wondering if this is a
good design for the syntax of the macro (comments about the
implementation are welcome too, of course, but the whole thing is
rather simple).

(defmacro frac (&rest arguments)
  "Fraction macro.  (frac a1 a2 ... :over b1 b2 ...) expands into
 (/ (* a1 a2 ...) (* b1 b2 ...)), with simplifications for
 single-element numerators or denominators."
  (unless (= (count :over arguments) 1)
    (error ":over should appear exactly once in arguments"))
  (flet ((expand (elements)		; expands product nicely
	   (cond ;; error for empty elements is deliberate, should not use frac
	     ((null elements) (error "numerator or denominator is empty"))
	     ((cadr elements) (cons 'cl:* elements))
	     (t (car elements)))))
    (let* ((position (position :over arguments :test #'eq))
	   (numerator (subseq arguments 0 position))
	   (denominator (subseq arguments (1+ position))))
      (write numerator)
      (write denominator)
      `(/ ,(expand numerator)
	  ,(expand denominator)))))

Examples:

(frac a b c :over d e) ; => (/ (* A B C) (* D E))
(frac a b c :over e) ; => (/ (* A B C) E)

Generally, I am asking about delimiting the arguments with keywords,
and parsing that -- is this good style, or does it have some ugliness
I have not considered yet?

Thanks,

Tamas

From: Chris Riesbeck
Subject: Re: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <73ndipFvgissU1@mid.individual.net>
Tamas K Papp wrote:
> I write a lot of fractions these days, and I am wondering if this is a
> good design for the syntax of the macro (comments about the
> implementation are welcome too, of course, but the whole thing is
> rather simple).
> 
> (defmacro frac (&rest arguments)
>   "Fraction macro.  (frac a1 a2 ... :over b1 b2 ...) expands into
>  (/ (* a1 a2 ...) (* b1 b2 ...)), with simplifications for
>  single-element numerators or denominators."
>   (unless (= (count :over arguments) 1)
>     (error ":over should appear exactly once in arguments"))
>   (flet ((expand (elements)		; expands product nicely
> 	   (cond ;; error for empty elements is deliberate, should not use frac
> 	     ((null elements) (error "numerator or denominator is empty"))
> 	     ((cadr elements) (cons 'cl:* elements))
> 	     (t (car elements)))))
>     (let* ((position (position :over arguments :test #'eq))
> 	   (numerator (subseq arguments 0 position))
> 	   (denominator (subseq arguments (1+ position))))
>       (write numerator)
>       (write denominator)
>       `(/ ,(expand numerator)
> 	  ,(expand denominator)))))
> 
> Examples:
> 
> (frac a b c :over d e) ; => (/ (* A B C) (* D E))
> (frac a b c :over e) ; => (/ (* A B C) E)
> 
> Generally, I am asking about delimiting the arguments with keywords,
> and parsing that -- is this good style, or does it have some ugliness
> I have not considered yet?

I agree with other postings about using / instead of :over, but on the 
parsing side of things, it's simpler and more efficient to use MEMBER 
and LDIFF, replacing the calls to COUNT, POSITION and SUBSEQ with

   (let* ((tail (member :over arguments))
          (numerator (ldiff arguments tail))
          (denominator (cdr tail)))
     (unless (and tail (not (member :over denominator)))
       (error ":over should appear exactly once in arguments"))
       ...remainder of code minus the inner LET*...
From: ··················@gmail.com
Subject: Re: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <4d19e030-666b-4724-bdf3-c7f71f5b2a55@f37g2000vbf.googlegroups.com>
On Apr 3, 4:40 pm, Tamas K Papp <······@gmail.com> wrote:
> I write a lot of fractions these days, and I am wondering if this is a
> good design for the syntax of the macro (comments about the
> implementation are welcome too, of course, but the whole thing is
> rather simple).
>
> (defmacro frac (&rest arguments)
>   "Fraction macro.  (frac a1 a2 ... :over b1 b2 ...) expands into
>  (/ (* a1 a2 ...) (* b1 b2 ...)), with simplifications for
>  single-element numerators or denominators."
>   (unless (= (count :over arguments) 1)
>     (error ":over should appear exactly once in arguments"))
>   (flet ((expand (elements)             ; expands product nicely
>            (cond ;; error for empty elements is deliberate, should not use frac
>              ((null elements) (error "numerator or denominator is empty"))
>              ((cadr elements) (cons 'cl:* elements))
>              (t (car elements)))))
>     (let* ((position (position :over arguments :test #'eq))
>            (numerator (subseq arguments 0 position))
>            (denominator (subseq arguments (1+ position))))
>       (write numerator)
>       (write denominator)
>       `(/ ,(expand numerator)
>           ,(expand denominator)))))
>
> Examples:
>
> (frac a b c :over d e) ; => (/ (* A B C) (* D E))
> (frac a b c :over e) ; => (/ (* A B C) E)
>
> Generally, I am asking about delimiting the arguments with keywords,
> and parsing that -- is this good style, or does it have some ugliness
> I have not considered yet?
>
> Thanks,
>
> Tamas

The style of the macro is fine, however that you are using a macro
here seems inappropriate.
It is not obvious to me how this is better than typing (/ (* a b c) (*
d e)). It seems kind of like macro for macro's sake. Decadence!
Excess!

Later on when someone is reading (i.e. debugging) they'll have to look
up the macro, make sure that it expands properly, all to save you two
or three keystrokes.

A better option might be to create a shortcut in your text editor (are
you using emacs?) that puts an empty (/ (* ) (* )) into your code, if
you really are doing a lot of fractions like this.

:-)
From: Mirko
Subject: Re: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <dda67d3c-91ab-404a-978c-e254271c946a@w40g2000yqd.googlegroups.com>
On Apr 3, 8:22 pm, ··················@gmail.com wrote:
> On Apr 3, 4:40 pm, Tamas K Papp <······@gmail.com> wrote:
>
>
>
> > I write a lot of fractions these days, and I am wondering if this is a
> > good design for the syntax of the macro (comments about the
> > implementation are welcome too, of course, but the whole thing is
> > rather simple).
>
> > (defmacro frac (&rest arguments)
> >   "Fraction macro.  (frac a1 a2 ... :over b1 b2 ...) expands into
> >  (/ (* a1 a2 ...) (* b1 b2 ...)), with simplifications for
> >  single-element numerators or denominators."
> >   (unless (= (count :over arguments) 1)
> >     (error ":over should appear exactly once in arguments"))
> >   (flet ((expand (elements)             ; expands product nicely
> >            (cond ;; error for empty elements is deliberate, should not use frac
> >              ((null elements) (error "numerator or denominator is empty"))
> >              ((cadr elements) (cons 'cl:* elements))
> >              (t (car elements)))))
> >     (let* ((position (position :over arguments :test #'eq))
> >            (numerator (subseq arguments 0 position))
> >            (denominator (subseq arguments (1+ position))))
> >       (write numerator)
> >       (write denominator)
> >       `(/ ,(expand numerator)
> >           ,(expand denominator)))))
>
> > Examples:
>
> > (frac a b c :over d e) ; => (/ (* A B C) (* D E))
> > (frac a b c :over e) ; => (/ (* A B C) E)
>
> > Generally, I am asking about delimiting the arguments with keywords,
> > and parsing that -- is this good style, or does it have some ugliness
> > I have not considered yet?
>
> > Thanks,
>
> > Tamas
>
> The style of the macro is fine, however that you are using a macro
> here seems inappropriate.
> It is not obvious to me how this is better than typing (/ (* a b c) (*
> d e)). It seems kind of like macro for macro's sake. Decadence!
> Excess!
>
> Later on when someone is reading (i.e. debugging) they'll have to look
> up the macro, make sure that it expands properly, all to save you two
> or three keystrokes.
>
> A better option might be to create a shortcut in your text editor (are
> you using emacs?) that puts an empty (/ (* ) (* )) into your code, if
> you really are doing a lot of fractions like this.
>
> :-)

I am guilty of the same (lambda (arg) (sqrt (- 1 (exp (cos arg) 2)))))
- every once in a while, I revisit old code and discover macros that
really can be done by functions.

Regarding the style of writing, I tend to format the (/ (* ) (* ))
forms in two lines:
(/ (* ...)
   (* ...))
This gives me an almost fraction-like look.

Mirko
From: Christopher C. Stacy
Subject: There are many copies [Re: macro design question -- delimiting the arguments with keywords]
Date: 
Message-ID: <yzl1vs86gkc.fsf_-_@news.dtpq.com>
··················@gmail.com writes:
> Later on when someone is reading (i.e. debugging) they'll have to look
> up the macro, make sure that it expands properly, all to save you two
> or three keystrokes.

They will have to look up that frac'n macro...
From: Tamas K Papp
Subject: Re: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <73ovkdF10ekrqU1@mid.individual.net>
On Fri, 03 Apr 2009 17:22:06 -0700, anonymous.c.lisper wrote:

> On Apr 3, 4:40 pm, Tamas K Papp <······@gmail.com> wrote:
>> Examples:
>>
>> (frac a b c :over d e) ; => (/ (* A B C) (* D E)) (frac a b c :over e)
>> ; => (/ (* A B C) E)
>>
>> Generally, I am asking about delimiting the arguments with keywords,
>> and parsing that -- is this good style, or does it have some ugliness I
>> have not considered yet?
>>
>> Thanks,
>>
>> Tamas
> 
> The style of the macro is fine, however that you are using a macro here
> seems inappropriate.
> It is not obvious to me how this is better than typing (/ (* a b c) (* d
> e)). It seems kind of like macro for macro's sake. Decadence! Excess!
> 
> Later on when someone is reading (i.e. debugging) they'll have to look
> up the macro, make sure that it expands properly, all to save you two or
> three keystrokes.
> 
> A better option might be to create a shortcut in your text editor (are
> you using emacs?) that puts an empty (/ (* ) (* )) into your code, if
> you really are doing a lot of fractions like this.

Hi everyone,

Thanks for all the answers.

The purpose of this syntax was not succinctness, but readability -- I
wanted such fractions to stand out.  I found that I find algebraic
expressions easier to navigate with it -- the project I am currently
working on had a lot of these.

I agree with Pascal's suggestion that this could be a function, but I
needed efficiency and so far I have not educated myself about compiler
macros, this will be a good opportunity.

Tamas
From: Kaz Kylheku
Subject: Re: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <20090412190017.781@gmail.com>
On 2009-04-03, Tamas K Papp <······@gmail.com> wrote:
> I write a lot of fractions these days,

Sign of the times.

> and I am wondering if this is a
> good design for the syntax of the macro (comments about the
> implementation are welcome too, of course, but the whole thing is
> rather simple).
>
> (defmacro frac (&rest arguments)
>   "Fraction macro.  (frac a1 a2 ... :over b1 b2 ...) expands into

Starting with (frac a1 a2 ... b1 b2 ...), the ":over " syntax adds six
characters, typed as six keystrokes, one shift.  A syntax based extra
parantheses adds four characters "()()" requiring no additional space: these
are typed as four strokes, typically accompanied by three shifts, since you can
hold the shift key through while typing ") (".

So if it is terseness you're trying to achieve, the :over syntax can't be
rationalized in favor of parens; you will need a shorter keyword. I suggest the
/ symbol.

  (frac a1 a2 ... / b1 b2 ...)

Why invent :over when you already have an operator symbol for denoting that
meaning?

FRAC could be called something else, like say //.

 (// a1 a2 ... / b1 b2)
From: Paul Donnelly
Subject: Re: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <87bprdxwq0.fsf@plap.localdomain>
Kaz Kylheku <········@gmail.com> writes:

> I suggest the / symbol.
>
>   (frac a1 a2 ... / b1 b2 ...)

I was going to say the same thing. Unless you've got a lot of variables
named /, it would be my first choice.
From: BubbaFrench
Subject: Re: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <1bc4c166-20cb-4bef-9470-16fc569714b0@j39g2000yqn.googlegroups.com>
On 4 апр, 00:40, Tamas K Papp <······@gmail.com> wrote:
> I write a lot of fractions these days, and I am wondering if this is a
> good design for the syntax of the macro (comments about the
> implementation are welcome too, of course, but the whole thing is
> rather simple).
>
> (defmacro frac (&rest arguments)
>   "Fraction macro.  (frac a1 a2 ... :over b1 b2 ...) expands into
>  (/ (* a1 a2 ...) (* b1 b2 ...)), with simplifications for
>  single-element numerators or denominators."
>   (unless (= (count :over arguments) 1)
>     (error ":over should appear exactly once in arguments"))
>   (flet ((expand (elements)             ; expands product nicely
>            (cond ;; error for empty elements is deliberate, should not use frac
>              ((null elements) (error "numerator or denominator is empty"))
>              ((cadr elements) (cons 'cl:* elements))
>              (t (car elements)))))
>     (let* ((position (position :over arguments :test #'eq))
>            (numerator (subseq arguments 0 position))
>            (denominator (subseq arguments (1+ position))))
>       (write numerator)
>       (write denominator)
>       `(/ ,(expand numerator)
>           ,(expand denominator)))))
>
> Examples:
>
> (frac a b c :over d e) ; => (/ (* A B C) (* D E))
> (frac a b c :over e) ; => (/ (* A B C) E)
>
> Generally, I am asking about delimiting the arguments with keywords,
> and parsing that -- is this good style, or does it have some ugliness
> I have not considered yet?
>
> Thanks,
>
> Tamas

People say here, that forward slash instead of keyword (/ instead
of :over) may look better, but I think, that such a substitution can
bring some ambiguity to this macro's use. Also, I agree, that use of
(/ (*) (*)) shall be more suitable. I think, that you may post a more
real-world related macro, so we could evaluate such a technique. I
mean, it looks fine, but maybe it can bring some uncertainity too.

And about delimiting, I don't know; maybe it would be better not to
delimit, but to group parameters. I mean, as it is usually used -
&optional, &keyword, etc.

In fact, if you look at both construction, delimiting can be always
replaced by grouping without any complications, but for me, grouping
seems to be more natural in Lisp, though I'm not a professional.
From: Pascal Costanza
Subject: Re: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <73ndojFvpn4lU1@mid.individual.net>
Tamas K Papp wrote:
> I write a lot of fractions these days, and I am wondering if this is a
> good design for the syntax of the macro (comments about the
> implementation are welcome too, of course, but the whole thing is
> rather simple).
> 
> (defmacro frac (&rest arguments)
>   "Fraction macro.  (frac a1 a2 ... :over b1 b2 ...) expands into
>  (/ (* a1 a2 ...) (* b1 b2 ...)), with simplifications for
>  single-element numerators or denominators."
>   (unless (= (count :over arguments) 1)
>     (error ":over should appear exactly once in arguments"))
>   (flet ((expand (elements)		; expands product nicely
> 	   (cond ;; error for empty elements is deliberate, should not use frac
> 	     ((null elements) (error "numerator or denominator is empty"))
> 	     ((cadr elements) (cons 'cl:* elements))
> 	     (t (car elements)))))
>     (let* ((position (position :over arguments :test #'eq))
> 	   (numerator (subseq arguments 0 position))
> 	   (denominator (subseq arguments (1+ position))))
>       (write numerator)
>       (write denominator)
>       `(/ ,(expand numerator)
> 	  ,(expand denominator)))))
> 
> Examples:
> 
> (frac a b c :over d e) ; => (/ (* A B C) (* D E))
> (frac a b c :over e) ; => (/ (* A B C) E)
> 
> Generally, I am asking about delimiting the arguments with keywords,
> and parsing that -- is this good style, or does it have some ugliness
> I have not considered yet?

Depending on circumstances, this interface could be defended, although 
it's not really necessary.

Note, however, that you're defining a macro for an operation that 
doesn't need to be a macro. In general, if you can define something as a 
function, it's preferable to do so, for example because functions are 
easier to debug. It's also recommendable to learn loop.

Here is a version:

(defun frac (&rest args)
   (declare (dynamic-extent args))
   (loop with state = 'numerator
         with numerator = 1
         with denominator = 1
         for arg in args
         if (eq arg :over) do (setq state 'denominator)
         else if (eq state 'numerator)
              do (setq numerator (* numerator arg))
         else do (setq denominator (* denominator arg))
         finally (assert (eq state 'denominator))
         (return (/ numerator denominator))))

If you are worried about efficiency, you can always define a compiler 
macro on top of a functional version:

(define-compiler-macro frac (&rest args)
   (loop with state = 'numerator
         for arg in args
         if (eq arg :over) do (setq state 'denominator)
         else if (eq state 'numerator) collect arg into numerator
         else collect arg into denominator
         finally (assert (eq state 'denominator))
         (return `(/ (* ,@numerator) (* ,@denominator)))))

In direct invocations of frac, this should now give you the same 
expansion as your original macro definition (if inlining is switched on 
and optimization settings are high).


Pascal

-- 
ELS'09: http://www.european-lisp-symposium.org/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: namekuseijin
Subject: Re: macro design question -- delimiting the arguments with keywords
Date: 
Message-ID: <721a11d7-3f51-46b7-916b-e6b6c8e9257d@o11g2000yql.googlegroups.com>
True.  Here's a Scheme version for the sake of completion:

; gets all i in ls until x
(define (until x ls)
  (reverse
   (call-with-current-continuation (lambda (k)
      (foldl (lambda (i o) (if (eq? x i) (k o) (cons i o)))
             '() ls)))))
; gets all i in ls from x on, excluding
(define (from x ls)
  (let ((r (member x ls)))
    (if (null? r) r
        (cdr r))))

(define (frak . args)
  (let ((nums (until 'over args))
        (denoms (from 'over args)))
    `(/ (* ,@nums) ,(if (= 1 (length denoms)) (car denoms) `
(* ,@denoms)))))

(frak 1 2 3 'over 4 5)
=> (/ (* 1 2 3) (* 4 5))

(frak 1 2 3 'over 4)
=> (/ (* 1 2 3) 4)

Not quite sure about the need for literal expressions rather than just
the results, though...

why not simply:
(define (// nums denoms) (/ (apply * nums) (apply * denoms)))
(// '(1 2 3) '(4 5))
=> 3/10
(/ (* 1 2 3) (* 4 5))
=> 3/10

beats the original by just one char or 2 if it was a macro. :P