From: livingcosmos.org
Subject: applying f to f n times - best argument order?
Date: 
Message-ID: <acaeca5b-43c6-4085-8dd1-0222ff3ebc81@i3g2000hsf.googlegroups.com>
Many thanks to tcr in #lisp for convincing me to improve this code to
handle multiple arguments. I disagreed with his idea that it should
take n as its first argument. he thought it was confusing, but I did
not see why:

(defun ncall (f n &rest data)
  "FUNCTION f -> INTEGER n -> d1 .. dn -> (f (f ... (apply f
data) ... ))"
  (if (= 1 n)
      (apply f data)
      (funcall f (ncall f (1- n) data))))

I wrote this because I had a function which prepended a single unit
axis onto an array. However I needed to append n axes onto the array
but didnt feel like modifyig the original function:

(defun prepend-unit-axis (n)
  "NOUN n -> NOUN n with prepended unit axis"
  (if (arrayp n)
      (let ((dims (array-dimensions n)))
	(make-array (cons 1 dims) :displaced-to (array->vector n)))
      (vector n)))


(ncall #'prepend-unit-axis 3 (vector 12 34))

From: ······@corporate-world.lisp.de
Subject: Re: applying f to f n times - best argument order?
Date: 
Message-ID: <3894e611-ef0c-47aa-93f3-8085a8381a65@s8g2000prg.googlegroups.com>
On Dec 25, 12:16 am, "livingcosmos.org" <········@gmail.com> wrote:
> Many thanks to tcr in #lisp for convincing me to improve this code to
> handle multiple arguments. I disagreed with his idea that it should
> take n as its first argument. he thought it was confusing, but I did
> not see why:
>
> (defun ncall (f n &rest data)
>   "FUNCTION f -> INTEGER n -> d1 .. dn -> (f (f ... (apply f
> data) ... ))"
>   (if (= 1 n)
>       (apply f data)
>       (funcall f (ncall f (1- n) data))))

The documentation for the function is confusing.

You say:

 "FUNCTION f -> INTEGER n -> d1 .. dn -> (f (f ... (apply f
data) ... ))"

But you don't apply f to data. You apply f n times to data that is n-1
times listified.

? (ncall #'print 4 1)

(((1)))
(((1)))
(((1)))
(((1)))
(((1)))

? (ncall #'print 4 1 2 3)

(((1 2 3)))
(((1 2 3)))
(((1 2 3)))
(((1 2 3)))
(((1 2 3)))


? (ncall #'list 4 1 2 3)
(((((((1 2 3)))))))

Your documentation would indicate something like this:

? (defun ncall (f n &rest data)
  "FUNCTION f -> INTEGER n -> d1 .. dn -> (f (f ... (apply f
data) ... ))"
  (if (= 1 n)
      (apply f data)
      (funcall f (apply #'ncall f (1- n) data))))
NCALL

? (ncall #'list 4 1 2 3)
((((1 2 3))))

? (ncall #'print 4 1)

1
1
1
1
1




I also don't think that style of documentation is best, since Common
Lisp does not
support implicit currying. Arglists are as specified and omitting an
argument does not
create a curried function.


>
> I wrote this because I had a function which prepended a single unit
> axis onto an array. However I needed to append n axes onto the array
> but didnt feel like modifyig the original function:
>
> (defun prepend-unit-axis (n)
>   "NOUN n -> NOUN n with prepended unit axis"
>   (if (arrayp n)
>       (let ((dims (array-dimensions n)))
>         (make-array (cons 1 dims) :displaced-to (array->vector n)))
>       (vector n)))
>
> (ncall #'prepend-unit-axis 3 (vector 12 34))
From: Kaz Kylheku
Subject: Re: applying f to f n times - best argument order?
Date: 
Message-ID: <07560856-6c99-47a1-8179-b3c6a50d75e0@b40g2000prf.googlegroups.com>
On Dec 24, 3:16 pm, "livingcosmos.org" <········@gmail.com> wrote:
> Many thanks to tcr in #lisp for convincing me to improve this code to
> handle multiple arguments. I disagreed with his idea that it should
> take n as its first argument. he thought it was confusing, but I did
> not see why:
>
> (defun ncall (f n &rest data)
>   "FUNCTION f -> INTEGER n -> d1 .. dn -> (f (f ... (apply f
> data) ... ))"
>   (if (= 1 n)
>       (apply f data)
>       (funcall f (ncall f (1- n) data))))

Surely, don't you mean:

  (funcall f (apply #'ncall f (1- n) data))

You want to bounce the arguments down into the recursive call, not a
list of them as one argument, right?

Is this what you are looking for:

 (defun ncall (f n &rest data)
   (loop repeat n
         for result = (apply f data) then (funcall f result)
         finally (return result)))

Handles large N without tail call optimization; returns NIL if N is
nonpositive.