Recursive lambda
флаг
Повідомлення 1 - 10 з 26 - Згорнути всі
/groups/adfetch?adid=_Z5afxEAAAAbKOqjTiHi-S28dCLoa8yXnT3luubDeskUok6AUQ17nQ
Група, до якої ви додаєте допис, - група Usenet. Відтак, будь-хто в Інтернеті бачитиме вашу електронну адресу.
Вашу відповідь не було надіслано.
Ваш допис надіслано
 
Від:
Кому:
Копія:
Продолжить:
Додати копію: | Додати продовження: | Редагувати тему
Тема:
Підтвердження:
З метою підтвердження введіть символи, наведені на зображенні нижче, або числа, які чуєте, натиснувши значок доступу. Прослухайте і введіть цифри, що чуєте
 
1.  Piotr Kuchta  
Переглянути профіль   Перекласти вказаною мовою: Перекладено (переглянути оригінал)
 Більше налаштувань 6 Лип 2001, 15:04
Групи новин: comp.lang.lisp
Від: "Piotr Kuchta" <pi...@itam.zabrze.pl>
Дата: Fri, 6 Jul 2001 13:54:46 +0200
Місцевий час: Пт 6 Лип 2001 14:54
Тема: Recursive lambda
Just curious: is it possible for a lambda (unnamed) function to call itself?

Regards,
Piotr


Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.
2.  Kalle Olavi Niemitalo  
Переглянути профіль   Перекласти вказаною мовою: Перекладено (переглянути оригінал)
 Більше налаштувань 6 Лип 2001, 16:30
Групи новин: comp.lang.lisp
Від: Kalle Olavi Niemitalo <k...@iki.fi>
Дата: 06 Jul 2001 16:17:46 +0300
Місцевий час: Пт 6 Лип 2001 16:17
Тема: Re: Recursive lambda

"Piotr Kuchta" <pi...@itam.zabrze.pl> writes:
> Just curious: is it possible for a lambda (unnamed) function to call itself?

You could give the function to itself as a parameter.
Although then it isn't really unnamed any more...

  (let ((unnamed (lambda (me obj)
                   (if (atom obj)
                       obj
                     (cons (funcall me me (cdr obj))
                           (funcall me me (car obj)))))))
    (funcall unnamed unnamed '(a b c)))

I'm not aware of a syntax for getting the innermost enclosing function.
I'd be surprised if there was one, as LET is almost a LAMBDA too.
&WHOLE arguments spring to mind, but IIRC those are for macros only.


Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.
Kalle Olavi Niemitalo <k...@iki.fi> writes:

Or use Ugly Macros. I have (once or twice) used something along the
lines of:
(defmacro fakelambda (args &body body)
 `(lambda ,args (labels ((me ,args ,@body)) (me ,@args))))

This lets you get to call "the unnamed lambda" as ME within its body.

//Ingvar
--
When C++ is your hammer, everything looks like a thumb
        Latest seen from Steven M. Haflich, in c.l.l


Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.
4.  Kalle Olavi Niemitalo  
Переглянути профіль   Перекласти вказаною мовою: Перекладено (переглянути оригінал)
 Більше налаштувань 6 Лип 2001, 18:00
Групи новин: comp.lang.lisp
Від: Kalle Olavi Niemitalo <k...@iki.fi>
Дата: 06 Jul 2001 17:53:46 +0300
Місцевий час: Пт 6 Лип 2001 17:53
Тема: Re: Recursive lambda

Ingvar Mattsson <ing...@bofh.se> writes:
> (defmacro fakelambda (args &body body)
>  `(lambda ,args (labels ((me ,args ,@body)) (me ,@args))))

This can't handle lambda list keywords.  A simple workaround would be:

  (defmacro fakelambda (lambda-list &body body)
    (let ((args (gensym)))
      `(lambda (&rest ,args)
         (labels ((me ,lambda-list ,@body))
           (apply #'me ,args)))))

but then the returned function can't be usefully inspected.  I wonder
if this can be made to work with supplied-p parameters and all that...
ah, now I get it!

  (defmacro fakelambda (lambda-list &body body)
    `(labels ((me ,lambda-list ,@body))
       #'me))

Functions made with LABELS have indefinite extent, right?  :-)


Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.
5.  Kent M Pitman  
Переглянути профіль   Перекласти вказаною мовою: Перекладено (переглянути оригінал)
 Більше налаштувань 6 Лип 2001, 19:24
Групи новин: comp.lang.lisp
Від: Kent M Pitman <pit...@world.std.com>
Дата: Fri, 6 Jul 2001 16:21:21 GMT
Місцевий час: Пт 6 Лип 2001 19:21
Тема: Re: Recursive lambda
Kalle Olavi Niemitalo <k...@iki.fi> writes:

There is none.  It's not really very well-defined.  It would defeat the
ability of other macros surrounding any given form to insert additional
layers of function-boundary for dataflow purposes.  Consider the problem
of introducing extra unnamed blocks around something.  RETURN returns to
the innermost block NIL, but we had to add BLOCK and RETURN-FROM in order
to have a transparent way to add extra blocks around a form without
interfering with people's expectations about where BLOCK boundaries would
be.  If we had the facility you're talking about, there would have to be
named and unnamed versions of "enclosing functions" in order to not
violate referential transparency.  Anyway, it's not done.

> I'd be surprised if there was one, as LET is almost a LAMBDA too.

I'm not sure what that means or why it's relevant, but see below.

> &WHOLE arguments spring to mind, but IIRC those are for macros only.

Yes, &whole is of no help here.  It would only point back to the source
form, not to the resulting function.  Forms are not callable.  A lambda
expression evaluates to a function, it is not itself a function.

The implementation in most Scheme implementations is the same as how
you'd do it in Lisp, they just don't tell you.

 (defmacro letrec (bindings &body forms)
   `(let ,(mapcar #'car bindings)
      (setq ,@(mapcan #'copy-list bindings))
       ,@forms))

The only difference is that in Common Lisp, because we have two namespaces,
you call a variable's value with funcall instead of like a function.

 (letrec ((fact (lambda (x)
                  (if (zerop x) 1
                      (* x (funcall fact (- x 1)))))))
   (funcall fact 6))
 => 720

Not that you couldn't put some syntactic sugar around that if
you wanted to.  Consider:

 (defmacro fletrec (bindings &body forms)
   (let ((temp (gensym)))
     `(let ,(mapcar #'car bindings)
       (flet ,(mapcar #'(lambda (binding)
                          (let ((name (car binding)))
                            `(,name (&rest ,temp)
                                (declare (dynamic-extent ,temp))
                                (apply ,name ,temp))))
                      bindings)
          (setq ,@(mapcan #'copy-list bindings))
         ,@forms))))

 (fletrec ((fact (lambda (x)
                   (if (zerop x) 1
                       (* x (fact (- x 1)))))))
   (fact 6))
 => 720


Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.
6.  Kalle Olavi Niemitalo  
Переглянути профіль   Перекласти вказаною мовою: Перекладено (переглянути оригінал)
 Більше налаштувань 7 Лип 2001, 19:34
Групи новин: comp.lang.lisp
Від: Kalle Olavi Niemitalo <k...@iki.fi>
Дата: 07 Jul 2001 16:08:55 +0300
Місцевий час: Сб 7 Лип 2001 16:08
Тема: Re: Recursive lambda
Kent M Pitman <pit...@world.std.com> writes:

> Kalle Olavi Niemitalo <k...@iki.fi> writes:
> > I'd be surprised if there was one, as LET is almost a LAMBDA too.

> I'm not sure what that means or why it's relevant, but see below.

I meant (LET ((VAR VAL)) BODY) = ((LAMBDA (VAR) BODY) VAL);
making LAMBDA also save the function for retrieval with
ENCLOSING-FUNCTION (or whatever it would be called) would break
the equivalence.

> Yes, &whole is of no help here.  It would only point back to the source
> form, not to the resulting function.  Forms are not callable.  A lambda
> expression evaluates to a function, it is not itself a function.

You can COERCE the lambda expression to a function... but then
you lose local bindings.  Hm.  Perhaps with &ENVIRONMENT and
EVAL...  except that's restricted to macros too.

>  (defmacro letrec (bindings &body forms)
>    `(let ,(mapcar #'car bindings)
>       (setq ,@(mapcan #'copy-list bindings))
>        ,@forms))

The indentation of ,@forms confused me for several minutes.

When you write macros in production code, do you make them
strictly check the syntax of arguments and signal errors for
things like (LETREC ((VAR 'VAL EXTRA)))?  Is DESTRUCTURING-BIND
good for that?

Is there a function like MAPCAN that would use APPEND rather than
NCONC, so that COPY-LIST wouldn't be needed?  I didn't find such
a thing in the HyperSpec.


Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.
7.  Kent M Pitman  
Переглянути профіль   Перекласти вказаною мовою: Перекладено (переглянути оригінал)
 Більше налаштувань 7 Лип 2001, 20:09
Групи новин: comp.lang.lisp
Від: Kent M Pitman <pit...@world.std.com>
Дата: Sat, 7 Jul 2001 17:06:39 GMT
Місцевий час: Сб 7 Лип 2001 20:06
Тема: Re: Recursive lambda
Kalle Olavi Niemitalo <k...@iki.fi> writes:

> When you write macros in production code, do you make them
> strictly check the syntax of arguments and signal errors for
> things like (LETREC ((VAR 'VAL EXTRA)))?  Is DESTRUCTURING-BIND
> good for that?

Sometimes I check, sometimes not.  The user is obliged, regardless,
not to put stuff there, so I consider it "helpful but optional" to
do that checking.

> Is there a function like MAPCAN that would use APPEND rather than
> NCONC, so that COPY-LIST wouldn't be needed?
> I didn't find such a thing in the HyperSpec.

There isn't any.

But there are about 117 other ways to win, so it's not like you're stuck.

LOOP has an appending collection mechanism.

And (reduce #'append lists) or (apply #'append lists) probably would have
done it.  I just used the first thing that came into my head.
In spite of what you've perhaps been told, NCONC is not evil nor to be
avoided, nor are all cases of COPY-LIST wasteful.
Note that these calls to COPY-LIST are (mostly) not doing extra copying--those
cons cells WILL be copied anyway even if
you use APPEND.  MAPCAN+COPY-LIST just makes the copying explicit...

I said "mostly" above in one place because my version did copy the last
pair of bindings "unnecessarily" ... but that seemed small matter.


Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.
8.  Kalle Olavi Niemitalo  
Переглянути профіль   Перекласти вказаною мовою: Перекладено (переглянути оригінал)
 Більше налаштувань 8 Лип 2001, 12:39
Групи новин: comp.lang.lisp
Від: Kalle Olavi Niemitalo <k...@iki.fi>
Дата: 08 Jul 2001 04:15:38 +0300
Місцевий час: Нд 8 Лип 2001 04:15
Тема: Re: Recursive lambda
Kent M Pitman <pit...@world.std.com> writes:

> In spite of what you've perhaps been told, NCONC is not evil nor to be
> avoided, nor are all cases of COPY-LIST wasteful.

I was thinking that COPY-LIST scans each list, and MAPCAN must
scan it again to find the end.  The slowdown pales to the time
spent compiling the result, but if there were an easy-to-use
operator that did the same thing with only one scan, I'd rather
use it.

> LOOP has an appending collection mechanism.

I see.  It's a bit verbose to use, though.

> And (reduce #'append lists) or (apply #'append lists) probably would have
> done it.

The first one needs :FROM-END T to avoid quadratic complexity.
Unfortunately, CMUCL 2.5.1 implements that by reversing the list
first, and consing is even worse than scanning.  Does any
implementation behave otherwise?  I don't see any obvious
algorithm.

The second one is bounded by CALL-ARGUMENTS-LIMIT.  (Is there any
such limit for the number of variables bound in a LET?)


Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.
9.  Kent M Pitman  
Переглянути профіль   Перекласти вказаною мовою: Перекладено (переглянути оригінал)
(1 користувач)  Більше налаштувань 8 Лип 2001, 19:20
Групи новин: comp.lang.lisp
Від: Kent M Pitman <pit...@world.std.com>
Дата: Sun, 8 Jul 2001 16:20:07 GMT
Місцевий час: Нд 8 Лип 2001 19:20
Тема: Re: Recursive lambda
Kalle Olavi Niemitalo <k...@iki.fi> writes:

> Kent M Pitman <pit...@world.std.com> writes:

> > In spite of what you've perhaps been told, NCONC is not evil nor to be
> > avoided, nor are all cases of COPY-LIST wasteful.

> I was thinking that COPY-LIST scans each list, and MAPCAN must
> scan it again to find the end.

This doesn't add materially to the algorithmic complexity of the operation.
An O(n) operation plus another O(n) operation is still O(n).

It's true that it adds a tiny amount of extra work in the rescan, but
really not worth fussing over unless this is the inner loop of some very
long computation.  In the case at hand, it just isn't, and any time spent
trying to fuss over further optimization is time wasted from your life.
Take the same time you would have spent optimizing such things and be home
for dinner just a little earlier, and you'll be happier all around.

> The slowdown pales to the time
> spent compiling the result, but if there were an easy-to-use
> operator that did the same thing with only one scan, I'd rather
> use it.

You could make one.  But the number of times you'd use it in your lifetime
might not add up to the time it takes you to write it.  Seriously, the time
to do optimizations of this nitpicking level (that is, operations that don't
improve the algorithmic complexity of code, but merely change tiny constant
factors in code that is hardly ever called) is when you have a product
delivered or about to be delivered and you think it's going to be unsuitable
for some customer if its speed is not enough.

Programmers waste too much of their lives optimizing things that do not
matter.  This means they are home late for dinner unnecessarily too often,
and it also means that even when they'd not be going home but would be
staying to work more, they're working more on the wrong things.  Computer
science has bigger problems than making this little piece of code fast.

> > LOOP has an appending collection mechanism.

> I see.  It's a bit verbose to use, though.

Learn to live with it.

I am not kidding.

Common Lisp is about doing things in practical ways.  LOOP, for all
its syntactic weirdness, is often the most practical in a number of
circumstnaces.  It really needs to be in your arsenal of things you're
willing to try, or you're crippling yourself.

If you really, really want to spend your whole life nitpicking about small
details and not ever getting on to the problems that are holding mankind
back, no one is stopping you.  But I can't stress strongly enough how little
I think this kind of thing matters and how important it is to learn to tell
the difference between things that do warrant careful scrutiny and things
that do not.

(It's not like I myself never obsess on things that don't matter, mind you.
I'm just hugely conscious of it, and waste a lot of time needlessly obsessing
about that, too...)

> > And (reduce #'append lists) or (apply #'append lists) probably would have
> > done it.

> The first one needs :FROM-END T to avoid quadratic complexity.

Right.   But even so, I was assuming this set of lists would be quite small
and so I just didn't worry a lot about that...

APPLY is probably the cheapest in this case if you know the set of
lists will always be short enough for it to work.  (There's a
limitation of how many lists you can use in APPLY because of
CALL-ARGUMENTS-LIMIT, as you note below.)

> Unfortunately, CMUCL 2.5.1 implements that by reversing the list
> first, and consing is even worse than scanning.  Does any
> implementation behave otherwise?  I don't see any obvious
> algorithm.

Well, it's possible to stack-allocate such a reversed list, so the gc
issue can be made a non-issue. Also, one can use real recursion (stacks)
to simulate the effect, again if you dont' mind pushing LOTS of stack.
Most gc experts will tell you, though, that consing that is immediately
dropped is gc'd quite efficiently by generational systems (which a lot
of people use), so the cost of just heap-allocating the reversed list and
discarding it isn't as great as you might think.

And, btw, optimization is almost always a per-vendor activity.  Each vendor
does it a different way.  It's good to talk here if a vendor says something
can't be optimized and you disagree and want suggestions.  But the standard
can't and doesn't specify optimizations.

Incidentally, even keyword calling (the :FROM-END T) can introduce extra
time into your calculation, but I recommend you also not worry about that
unless it gets out of hand.  In principle, an implementation can optimize
that out.  In practice, most just focus on the common cases and leave the
others for a rainy day.

> The second one is bounded by CALL-ARGUMENTS-LIMIT.  (Is there any
> such limit for the number of variables bound in a LET?)

No.  The compiler is supposed to split the LET if it needs to, though
you might find implementations with bugs.  I've certainly seen compilers
with little notes in them saying "I'll fix this when someone first
reports the bug".

-- -- --

To be clear:

 * I think it's good for vendors to care about this kind of speed issue.

 * I think it's ok for users to care about this kind of speed issue
   if it is a known bottleneck in a real application.

 * I think the rest of the time, users should mostly program as if
   something is going to be fast and send bug reports when it doesn't
   turn out to be.


Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.
10.  Kalle Olavi Niemitalo  
Переглянути профіль   Перекласти вказаною мовою: Перекладено (переглянути оригінал)
 Більше налаштувань 9 Лип 2001, 03:59
Групи новин: comp.lang.lisp
Від: Kalle Olavi Niemitalo <k...@iki.fi>
Дата: 08 Jul 2001 23:40:41 +0300
Місцевий час: Нд 8 Лип 2001 23:40
Тема: Re: Recursive lambda
Kent M Pitman <pit...@world.std.com> writes:

> Kalle Olavi Niemitalo <k...@iki.fi> writes:

> > Kent M Pitman <pit...@world.std.com> writes:
> > > LOOP has an appending collection mechanism.

> > I see.  It's a bit verbose to use, though.

> Learn to live with it.

Oh, I do use LOOP.  In this situation however, I feel the
verbosity of LOOP outweighs the minimal speedup.

Ви мусите увійти перед публікацією повідомлень.
Аби надіслати допис, будь ласка, спочатку приєднайтеся до цієї групи.
Будь ласка, поновіть своє прізвисько на сторінці налаштування передплати перед тим, як надіслати свій допис.
У вас немає права надсилання дописів до цієї групи.

Створити групу - Групи Google - Домашня сторінка Google - Правила користування послугою - Заява про конфіденційність і нерозголошення інформації
©2009 Google