Warning: mysqli::__construct(): (HY000/1203): User howardkn already has more than 'max_user_connections' active connections in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\includes\artfuncs.php on line 21
Failed to connect to MySQL: (1203) User howardkn already has more than 'max_user_connections' active connections
Warning: mysqli::query(): Couldn't fetch mysqli in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\index.php on line 66
Article <87o782h5mh.fsf@axel-reichert.de>
Deutsch   English   Français   Italiano  
<87o782h5mh.fsf@axel-reichert.de>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: Axel Reichert <mail@axel-reichert.de>
Newsgroups: comp.lang.lisp
Subject: Tail call recursion macro with named-let in Emacs Lisp (was: A simple lisp problem.)
Date: Sat, 15 Jun 2024 12:17:42 +0200
Organization: A noiseless patient Spider
Lines: 107
Message-ID: <87o782h5mh.fsf@axel-reichert.de>
References: <v4j2p1$3a0lu$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain
Injection-Date: Sat, 15 Jun 2024 12:17:45 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="ecc537ebfc5213417124a7d49f80461d";
	logging-data="3599724"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX1+7OHUeTZeUZhFwtl3sheiI2hxOgdBb2rM="
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux)
Cancel-Lock: sha1:EUzXnOCANkfSpnPRn7tT+1oIZQ0=
	sha1:3HsDE+X2aP56zMsPdpTBfA5uypM=
Bytes: 3880

"B. Pym" <No_spamming@noWhere_7073.org> writes:

> Frank Schwieterman wrote:
>
>> (defun difference (param)
>>      (if (> (length param) 1)
>>         (if (<= (abs (- (first param) (first (rest param)))) 1 )
>>            (difference (rest param))
>>            nil
>>            )
>>         T
>>         )
>>      )
>
> Gauche Scheme
>
> (define (diff1? xs)
>   (every
>     (lambda (a b) (= 1 (abs (- a b))))
>     xs
>     (cdr xs)))
>
> (diff1? '(2 3 4 3 4 5 6 7 8 9 8))
>   ===>
> #t
> (diff1? '(2 3 4 3 4 5 6 7 8 9 8 0))
>   ===>
> #f

A nice, recursive solution in Emacs Lisp would be

  (defun single-step-p (xs)
    (cond ((null (cdr xs)) t)
          ((= 1 (abs (- (car xs) (cadr xs)))) (single-step-p (cdr xs)))
          (t nil)))

but it fails for longer lists such as

  (single-step-p (number-sequence 1 1000))

because Emacs Lisp does not have proper tail call elimination. There is
an exception, though, "named-let", see here:

  https://www.gnu.org/software/emacs/manual/html_node/elisp/Local-Variables.html

So I rewrote the function to

  (defun single-step-p (xs)
    (named-let single-step-p ((xs xs)) 
      (cond ((null (cdr xs)) t)
            ((= 1 (abs (- (car xs) (cadr xs)))) (single-step-p (cdr xs)))
            (t nil))))

which work fine also for

  (single-step-p (number-sequence 1 1000000))

but of course looks a bit redundant compared to the "normal" use of
"named-let" for helper functions such as accumulating results etc.

So I wrote a small macro doing the wrapping in a "named-let" for me:

  (defmacro defun-tco-1 (name args body)
    `(defun ,name ,args
       (named-let ,name (,args ,args)
         ,body)))

Now

  (defun-tco-1 single-step-p (xs)
    (cond ((null (cdr xs)) t)
          ((= 1 (abs (- (car xs) (cadr xs)))) (single-step-p (cdr xs)))
          (t nil)))

works, but the macro of course fails for a different number of
arguments, as can be seen with

  (macroexpand-1 '(defun-tco-1 foo (a b) (+ a b)))

which gives

  (defun foo (a b) (named-let foo ((a b) (a b)) (+ a b)))

and of course also wrong results (14 instead of 10) for

  (foo 3 7)
  
So I needed to loop through the args of the macro and construct the
proper bindings for the "named-let":

  (defmacro defun-tco (name args body)
    (let ((bindings (mapcar #'(lambda (arg) (list arg arg)) args)))
      `(defun ,name ,args
         (named-let ,name ,bindings
           ,body))))

Is this fine from the point of the experts here (in fact, it is my first
macro that is unrelated to any macro tutorials/book, but rather came
from my own needs)? I am quite sure that I could suffer from variable
capture and perhaps also from multiple evaluation, but this would be the
second step for me after a first, general criticism here.

Many thank for any comments!

Best regards

Axel