infix via code walker hook.

Liste des GroupesRevenir à cl lisp 
Sujet : infix via code walker hook.
De : 643-408-1753 (at) *nospam* kylheku.com (Kaz Kylheku)
Groupes : comp.lang.lisp
Date : 31. Mar 2025, 22:24:03
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <20250331141507.905@kylheku.com>
User-Agent : slrn/pre1.0.4-9 (Linux)
I've been toying with the idea for a while of using a code walker
or hooking into an existing code walker in order to support S-exp-ified
infix syntax for arithmetic.

I have an advanced proof of concept happening.

What is interesting here is that the work gives rise to a powerful
argument in favor of the separation of function and variable bindings,
which helps to make it trivial:

  $ ./txr -i infix.tl
  TXR's no-spray organic production means every bug is carefully removed by hand.
  1> (ifx (let ((a 1) (b 2) (c 3))
            ((a + b) * 3)))
  9

Notice how ifx "works through" the let (and trust me when I say, any layering
of syntax it is not interested in).

ifx will find all infix expressions in its interior and transform them
based on the pattern (arg1 op [arg ...]) to (op arg1 [arg ...]).

This is the complete implementation, but relies on an unreleased
*expand-hook* feature:

  (defun-match infix-expand-hook
    ((@(as form (@x @y . @rest)) @env nil)
     (if (fboundp y)
       ^(,y ,x ,*rest)
       form))
    ((@form @nil @nil) form))

  (defmacro ifx (:env env . body)
    (let ((*expand-hook* (fun infix-expand-hook)))
      (expand ^(progn ,*body) env)))

The implementation's macro-expanding code-walker invokes *expand-hook*
for each macro (symbol or compound), function call or malformed form
that it encounters. It passes the form, the macro-expansion-time
environment, and a type symbol. The type symbol is :macro when the
form is a macro invocation, :fun if it is a function call, or else
nil if it is invalid.

The above infix module won't make the transformation on a form
that looks valid. Concretely, if you define a function a, whether
globally or locally, then (a + b) will not be transformed.

As you can see, this also showcases the benefits of a function/variable
namespace separation in Lisp. Even though a has a binding, (a + b) can
be transformed to (+ a b). This is because its binding is a variable
binding, which we can ignore.

In a Lisp-1 like Clojure or Scheme, there is a difficulty here:
we have to determine that a is not a function. That requires
type information or else a run-time check. The latter is a nonstarter,
since we are looking to transform code at macro time.
But even if you have the former, type info, who is to say that is
correct; maybe someone wants (f + g) where those are functions.

Here is a toast to variable/function namespace separation.

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

Date Sujet#  Auteur
31 Mar 25 * infix via code walker hook.9Kaz Kylheku
2 Apr 25 `* Re: infix via code walker hook.8Kaz Kylheku
4 Apr 25  `* Re: infix via code walker hook.7Kaz Kylheku
4 Apr 25   `* Re: infix via code walker hook.6Stefan Monnier
4 Apr 25    `* Re: infix via code walker hook.5Kaz Kylheku
4 Apr 25     `* Re: infix via code walker hook.4Stefan Monnier
5 Apr 25      +- Re: infix via code walker hook.1Kaz Kylheku
5 Apr 25      `* Re: infix via code walker hook.2Stefan Ram
5 Apr 25       `- Re: infix via code walker hook.1Kaz Kylheku

Haut de la page

Les messages affichés proviennent d'usenet.

NewsPortal