Rocksolid Light

News from da outaworlds

mail  files  register  groups  login

Message-ID:  

You will wish you hadn't.


comp / comp.lang.python / @Memoize doesn't work in Python 3 ? -- (Gauche scheme?)

SubjectAuthor
* @Memoize doesn't work in Python 3 ? -- (Gauche scheme?)HenHanna
`- Re: @Memoize doesn't work in Python 3 ? -- (Gauche scheme?)Kaz Kylheku

1
Subject: @Memoize doesn't work in Python 3 ? -- (Gauche scheme?)
From: HenHanna
Newsgroups: comp.lang.python, comp.lang.lisp, comp.lang.misc
Organization: A noiseless patient Spider
Date: Mon, 29 Jul 2024 18:42 UTC
Path: eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: HenHanna@devnull.tb (HenHanna)
Newsgroups: comp.lang.python,comp.lang.lisp,comp.lang.misc
Subject: @Memoize doesn't work in Python 3 ? -- (Gauche scheme?)
Date: Mon, 29 Jul 2024 11:42:32 -0700
Organization: A noiseless patient Spider
Lines: 28
Message-ID: <v88nqo$jkm6$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Mon, 29 Jul 2024 20:42:33 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="cda7bbd820da97e0a9151b7b6d2c87f6";
logging-data="643782"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/hl7kjy30HgB7w5Ma44r0eJY4qTHj7Ifs="
User-Agent: Mozilla Thunderbird
Cancel-Lock: sha1:jqOdgo+U5Nc3NjBZ3QYK6EW0Qr4=
Content-Language: en-US
View all headers

@Memoize doesn't work in Python 3 ?

Do we have this in Gauche scheme? (Common Lisp?)

___________________________

A feature known as "decorators" was added in Python 2.4

@Memoize
def factorial(k):
if k < 2: return 1
return k * factorial(k - 1)

__________________________

Python 3.9 released a new function functools.cache.
It caches in memory the result of a function called with a particular
set of arguments.

import functools
import time

@functools.cache
def calculate_double(num):
time.sleep(1) # sleep for 1 second to simulate a slow calculation
return num * 2

Subject: Re: @Memoize doesn't work in Python 3 ? -- (Gauche scheme?)
From: Kaz Kylheku
Newsgroups: comp.lang.python, comp.lang.lisp, comp.lang.misc
Organization: A noiseless patient Spider
Date: Mon, 29 Jul 2024 23:05 UTC
References: 1
Path: eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: 643-408-1753@kylheku.com (Kaz Kylheku)
Newsgroups: comp.lang.python,comp.lang.lisp,comp.lang.misc
Subject: Re: @Memoize doesn't work in Python 3 ? -- (Gauche scheme?)
Date: Mon, 29 Jul 2024 23:05:15 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 130
Message-ID: <20240729153816.517@kylheku.com>
References: <v88nqo$jkm6$1@dont-email.me>
Injection-Date: Tue, 30 Jul 2024 01:05:15 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="f0bf4dfe7b2a602a6b6f6b338f60bf44";
logging-data="724253"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19fTV+oQijoLwF0nbQ1XPzIdvdsch9IPdw="
User-Agent: slrn/pre1.0.4-9 (Linux)
Cancel-Lock: sha1:OLx35bjxuMt/lnFyhZ2em/hwYv8=
View all headers

On 2024-07-29, HenHanna <HenHanna@devnull.tb> wrote:
>
> @Memoize doesn't work in Python 3 ?
>
> Do we have this in Gauche scheme? (Common Lisp?)

In TXR Lisp there is something called parameter list macros,
or parameter macros, for short.

It is my invention.

Parameter list macros are named after keyword symbols.

When a keyword symbol occurs at the head of a macro or lambda
parameter list, if that symbol has a parameter macro binding,
the expander is invoked. The expander takes four arguments:
the parameter list, the body, a macro environmet and the entire
form that is defining the function (for error reporting).

The expander must produce a transformed parameter list, and
transformed function body.

No memoizing parameter macro is included in the language,
but the manual gives an example of how to write one. Excerpt:

The following example shows the implementation of a parameter
macro :memo which provides rudimentary memoization. Using the
macro is extremely easy. It is a matter of simply inserting the
:memo keyword at the front of a function's parameter list. The
function is then memoized.

(defvarl %memo% (hash :weak-keys))
(defun ensure-memo (sym)
(or (gethash %memo% sym)
(sethash %memo% sym (hash))))

(define-param-expander :memo (param body)
(let* ((memo-parm [param 0..(posq : param)])
(hash (gensym)) (key (gensym)))
^(,param (let ((,hash (ensure-memo ',hash))
(,key (list ,*memo-parm)))
(or (gethash ,hash ,key)
(sethash ,hash ,key (progn ,*body)))))))

The above :memo macro may be used to define a memoized Fibonacci
function as follows:

(defun fib (:memo n)
(if (< n 2)
(clamp 0 1 n)
(+ (fib (pred n)) (fib (ppred n)))))

All that is required is the insertion of the :memo keyword.

Not shown in the example is that :memo only memoizes over the
required parameters (ones before the colon : symbol that separates
fixed from optional). :memo does nothing with the parameters; they
are returned as is.

TXR Lisp does not have keywords in the native function calling model, but
provides a :key parameter macro that implements them via code transformation.
This uses -- to separate the specification of key parameters:

(lambda (:key a b c -- foo bar (xyzzy 42))
...)

There is no strict checking (i.e. what you opt out of in Common Lisp
by means of &allow-other-keys).

The entire implementation is here:

https://www.kylheku.com/cgit/txr/tree/stdlib/keyparams.tl

An interesting observation is that TXR Lisp also has a defset
macro (similar to Common Lisp defsetf).

When you use defset to define a place with keywords, it
Just Works, even though defset knows nothing about :key at all.

Like in the test cases related to (defset :foo ...)
in this file:

https://www.kylheku.com/cgit/txr/tree/tests/012/defset.tl

I was blown away, not expecting that to work.

Given

(defset foo (:key x y -- a b c (d 4)) n ^(bar ,x ,y, a, b, c ,d ,n))

With the defset macro having no knowledge of the existence of :key,
this works:

(inc (foo 1 2 :a 3 :b 4) 5) ;; increment (foo ...) place by 5

producing an expansion like:

(let ((#:new-value (+ (foo 1 2 :a 3 :b 4) 5)))
(bar 1 2 3 4 () 4 #:new-value)))

The :a and :b key values are decoded and inserted in the right spot in the (bar
form), and this happens when the place defined by defset is expanded by a
place-mutating form like inc.

More complex example showing that the arguments are evaluated just
once by the increment operation:

2> (expand '(inc (foo (one) (two) :a (three) :b (four)) 5))
(let ((#:g0074 (one))
(#:g0075 (two))
(#:g0076 (three))
(#:g0077 (four)))
(let ((#:g0026 (+ (foo #:g0074
#:g0075 :a
#:g0076 :b
#:g0077)
5)))
(bar #:g0074
#:g0075 #:g0076
#:g0077 ()
4 #:g0026)))

Common Lisp implementations of defsetf typically fudge around with keyword
argument parsing in order to make stuff like this work.

--
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca

1

rocksolid light 0.9.8
clearnet tor