• @Memoize doesn't work in Python 3 ? -- (Gauche scheme?)

    From HenHanna@3:633/280.2 to All on Tue Jul 30 04:42:32 2024

    @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


    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)
  • From Kaz Kylheku@3:633/280.2 to All on Tue Jul 30 09:05:15 2024
    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

    --- MBSE BBS v1.0.8.4 (Linux-x86_64)
    * Origin: A noiseless patient Spider (3:633/280.2@fidonet)