From: ·········@math.ufl.edu
Subject: Making my operations context-dependent (RINGS)
Date: 
Message-ID: <1187551296.288625.160180@k79g2000hse.googlegroups.com>
Dear Cognoscenti

I am starting a Number Theory project, primarily for
generating examples in the classroom, using bignums and
rational-numbers in CL.

I'll be posting some "beginner" questions, because I've found that
I've forgotten what little I knew; I am relearning CL, v*e*r*y
slowly, and have been getting tangled up with `defpackage', and
package-management in general.  [It is also clear that I have
forgotten how to ask short questions, but that too will come back
with practice.]

================

I'd like to define various rings, e.g, the ring of
polynomials in one variable.   Or the field of polynomials
modulo a particular irreducible polynomial.


Concretely, let's suppose I have written these packages:

    RING-POLY :
      Implements arithmetic operations in the polynomial ring.
    Internally the routines are named `ROP+' (for the Ring
    OPeration of addition), `ROP*', `ROP-ISZERO-P' and so on.

    RING-MOD5 :
      Implements arithmetic operations in the integers-mod-5.
    Internally the routines are named by the same names, `ROP+'
    (for addition mod-5), etc.

So RING-POLY::ROP+ adds two polynomials, whereas
RING-MOD5::ROP+ adds two integers mod-5.

There are various other packages, say

    MATRIX :
      for putting a matrix in reduced-row-echelon form.

First question: In package RING-POLY, I need to define FOO (i.e,
  RING-POLY::FOO) that calls external routine MATRIX:RREF.
  This latter's code uses  ROP+ and ROP* and so on.

  How do I set things up so that, when _loading_ package RING-POLY and
  consequently defining FOO, that each occurrence of ROP+ in this call
to
  MATRIX:RREF actually _means_ RING-POLY::ROP+ ?

    And similarly, when loading RING-MOD5 that each of occurrence of
ROP+ in
  a call to MATRIX:RREF actually _means_ RING-MOD5::ROP+  ?

[I realize that perhaps the routines in MATRIX  could all be written
as
macros, rather than functions.  But I'd just as soon have MATRIX
written
as if there is only one ring in the world, and MATRIX is just a bunch
of
functions that use this ring's operations.]


Second question:  (This is a generalization of the first.)  After
having
done

>  (in-package "COMMON-LISP-USER")
>  (use-package "RING-POLY")
>  (use-package "RING-MOD5")
>  (use-package "MATRIX")

I'd like to able to write something like the following:

>  (compute-value-using-ring "RING-POLY"
    (RREF some-matrix ) )

where COMPUTE-VALUE-USING-RING sets up a temporary context  where the
routines in MATRIX, when referring to ROP+, are somehow actually using
RING-POLY::ROP+ .

================================================================
Comments:

0: For the time being, I am pretending that none of the routines RING-
POLY::ROP+
need to refer to arithmetic operations in other, simpler rings.  This
isn't
actually true, but I'm already confused by the simpler situation.


1: Some time ago, I did something similar in EL [emacs lisp], using a
pointer to
(something like) structs whose entries were the various arithmetic
operations.

  Firstly, I found this clumsy.  Secondly, since CL has a real package
system, and
since the different (defstruct)s would be occurring in different RING
packages,
then their slot names [this is something I'm confused about] would
actually be
different symbols [due to the package-name component], so I'm not sure
how I'd
refer to them generically inside of the MATRIX code.


2: I'd like MATRIX to not know of the existence of multiple rings.  So
I'd
just as soon _not_ have the routines in MATRIX have to have a
"current-ring"  parameter that is passed-in.


3: The data is not typed.  I.e, my situation doesn't have the
complexity that
ROP+ has to look at its arguments and say "Ah --you folks are
polynomials. So
now I know how to add you".

  Rather, the _context_ that a ROP routine is called-in should
determine which
ring it is.  As an example, suppose M is a matrix, with each entry a
list, such
as ( 2/3 , 9 , 4).  Called in the context of RING-POLY, such an entry
is
interpreted as the polynomial

	2/3 + 9x +  4x^2.

But called in the context of RING-RATIONALS-WITH-BAGGAGE, the same
list ( 2/3 , 9 , 4) is simply interpreted as the number 2/3, where
the "9" and "4" are some auxiliary data that just goes along
for the ride.

   Sincerely, -Jonathan King

--
Prof. Jonathan LF King	 Mathematics dept, Univ. of Florida
<squash[[AT]]math.ufl.edu>,	 <http://www.math.ufl.edu/~squash/>

From: Matthias Benkard
Subject: Re: Making my operations context-dependent (RINGS)
Date: 
Message-ID: <1187554995.198333.91850@a39g2000hsc.googlegroups.com>
Hi,

As I don't have much time right now, I'm going to quickly hack
something up without actually reading all of your post, so...  sorry
if this turns out to be completely off-topic. :)

> I'd like to able to write something like the following:
>
> >  (compute-value-using-ring "RING-POLY"
>     (RREF some-matrix ) )
>
> where COMPUTE-VALUE-USING-RING sets up a temporary context  where the
> routines in MATRIX, when referring to ROP+, are somehow actually using
> RING-POLY::ROP+ .

You could use special variables:

(in-package matrix)

(defvar *rop+*)
(defvar *rop**)

(defun rop+ (&rest args)
  (apply *rop+* args))

(defun rop* (&rest args)
  (apply *rop** args))

...

You call these functions in the MATRIX routines.  Then, you define a
macro WITH-RING-OPERATIONS, also in package MATRIX:

(defmacro with-ring-operations ((+-op *-op) &body body)
  `(let ((*rop+* ,+-op)
         (*rop** ,*-op))
     ,@body))

You would call the macro like this:

(with-ring-operations (#'ring-poly::+-op #'ring-poly::*-op)
  (RREF some-matrix ...) ...)

Maybe you could even implement your COMPUTE-VALUE-USING-RING macro
(I'm calling it WITH-RING here; caution: this is completely untested!
I can only hope it's not fundamentally wrong):

(defmacro with-ring ((package-designator) &body body)
  `(with-ring-operations (,(fdefinition (find-symbol "ROP+" (package-
name package-designator)))
                          ,(fdefinition (find-symbol "ROP*" (package-
name package-designator))))
     ,@body))

This is an ugly hack if you ask me, though.  You'd probably be better
served with something like ContextL that actually has a concept of
special functions, which is what I'm trying to simulate here (or so I
hear -- I've never used ContextL myself, although it's on my to-do
list :))).

Hope this helps,
~ Matthias
From: Pascal Costanza
Subject: Re: Making my operations context-dependent (RINGS)
Date: 
Message-ID: <5irmcgF3qc4bnU1@mid.individual.net>
·········@math.ufl.edu wrote:
> Dear Cognoscenti
> 
> I am starting a Number Theory project, primarily for
> generating examples in the classroom, using bignums and
> rational-numbers in CL.
> 
> I'll be posting some "beginner" questions, because I've found that
> I've forgotten what little I knew; I am relearning CL, v*e*r*y
> slowly, and have been getting tangled up with `defpackage', and
> package-management in general.  [It is also clear that I have
> forgotten how to ask short questions, but that too will come back
> with practice.]

What you seem to want to do is not possible with packages. Package 
references are resolved at read time, but you want a change of function 
references at runtime.

With plain Common Lisp, you could probably use generic functions that 
dispatch on the kind of ring operations that you want. However, this 
violates your requirement that the matrix operations are not aware that 
potentially different ring operations are used in the first.

What you describe rather sounds like an excellent use case for ContextL. 
You may want to it check it out at 
http://common-lisp.net/project/closer/contextl.html

Please contact me if you have any questions. If ContextL actually turns 
out to be useful, I would also like to hear about it...


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Rainer Joswig
Subject: Re: Making my operations context-dependent (RINGS)
Date: 
Message-ID: <joswig-833296.23034319082007@news-europe.giganews.com>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> ·········@math.ufl.edu wrote:
> > Dear Cognoscenti
> > 
> > I am starting a Number Theory project, primarily for
> > generating examples in the classroom, using bignums and
> > rational-numbers in CL.
> > 
> > I'll be posting some "beginner" questions, because I've found that
> > I've forgotten what little I knew; I am relearning CL, v*e*r*y
> > slowly, and have been getting tangled up with `defpackage', and
> > package-management in general.  [It is also clear that I have
> > forgotten how to ask short questions, but that too will come back
> > with practice.]
> 
> What you seem to want to do is not possible with packages. Package 
> references are resolved at read time, but you want a change of function 
> references at runtime.
> 
> With plain Common Lisp, you could probably use generic functions that 
> dispatch on the kind of ring operations that you want. However, this 
> violates your requirement that the matrix operations are not aware that 
> potentially different ring operations are used in the first.

While this will not answer the OP's question, it might
be still interesting to look at the following two
CLOS-based systems (Weyl and Kenzo) for inspiration:

Kenzo.
http://www-fourier.ujf-grenoble.fr/~sergerar/Kenzo/

Weyl is a part of SimLab
http://www.cs.cornell.edu/Info/Projects/SimLab/releases/release-1-0.html
The release includes source and documentation.
The Weyl Computer Algebra Substrate 
http://ecommons.library.cornell.edu/bitstream/1813/6917/1/90-1077.pdf

> 
> What you describe rather sounds like an excellent use case for ContextL. 
> You may want to it check it out at 
> http://common-lisp.net/project/closer/contextl.html
> 
> Please contact me if you have any questions. If ContextL actually turns 
> out to be useful, I would also like to hear about it...
> 
> 
> Pascal

-- 
http://lispm.dyndns.org
From: Jens Axel Søgaard
Subject: Re: Making my operations context-dependent (RINGS)
Date: 
Message-ID: <46CA9A06.7000309@soegaard.net>
·········@math.ufl.edu wrote:
> Dear Cognoscenti
> 
> I am starting a Number Theory project, primarily for
> generating examples in the classroom, using bignums and
> rational-numbers in CL.
> 
> I'll be posting some "beginner" questions, because I've found that
> I've forgotten what little I knew; I am relearning CL, v*e*r*y
> slowly, and have been getting tangled up with `defpackage', and
> package-management in general.  [It is also clear that I have
> forgotten how to ask short questions, but that too will come back
> with practice.]

Your question reminds me of this thread in sci.math.symbolic.
This example shows one way to organize the code in PLT Scheme:

     <http://2url.org/?ringexample>

-- 
Jens Axel S�gaard
From: ·········@math.ufl.edu
Subject: Re: Making my operations context-dependent (RINGS)
Date: 
Message-ID: <1187711067.692725.4390@r29g2000hsg.googlegroups.com>
Thank you, Pascal, Matthias, Rainer and Jens, for your replies.
  You have given me several reading assignments, which I will do as
soon as
I can.  [The semester here begins tomorrow.]

  If what I'm looking for can't be done easily in CL, then this means
I've mis-specified or over-specified the problem.  I have an idea
for a partial (but perhaps inefficient) solution using `flet' and
`defmacro', which I will post in a few days.

But this leads me to a question about `flet' and `defmacro'.  I'll
use these macros to ask the question:

  (defmacro me     (&rest form) `(macroexpand-1   ',@form))
  (defmacro mefull (&rest form) `(macroexpand     ',@form))
  (defmacro metoo  (&rest form) `(EXT:EXPAND-FORM ',@form))

I read about `EXT:EXPAND-FORM' in this N.G.; it may be specific to
CLISP.
================================================================

In a fresh CLISP, I execute the above macro defs.  Then the
following gives this [slightly edited] output:

  (defmacro mac (x) ` (list ,x ,x ,x))  =>  MAC

  (metoo (list (let ((z 7)) (mac z)) (flet ((mac (z)  (+ z 7))) (mac
100))))
    =>
  (LIST
   (LET ((Z 7)) (LIST Z Z Z))
   (FLET
    ((MAC (Z) (DECLARE (SYSTEM::SOURCE ((Z) (BLOCK MAC (+ Z 7))))) (+
Z 7)))
    (MAC 100)))

Executing the argument to `metoo' gives

  (list (let ((z 7)) (mac z)) (flet ((mac (z)  (+ z 7))) (mac 100)))
    =>
  ((7 7 7) 107)

So the call to `(mac z)' inside of `let' is macro-expanded, and the
call to `(mac 100)' inside the `flet' is not macro-expanded.

This makes sense to me; could someone tell me where this is said in
either the book CLTL2 or at "http://www.lisp.org/HyperSpec/"?

Here is a paragraph from

  http://www.lisp.org/HyperSpec/Body/speope_fletcm_scm_macrolet.html

that says:

  "The names of functions defined by flet are in the lexical
  environment; they retain their local definitions only within the
  body of flet. The function definition bindings are visible only in
  the body of flet, not the definitions themselves. Within the
  function definitions, local function names that match those being
  defined refer to functions or macros defined outside the flet. flet
  can locally shadow a global function name, and the new definition
  can refer to the global definition."

Is the sentence

  "flet can locally shadow a global function name, and
   the new definition can refer to the global definition."

implying that the `(mac 100)' is not to be macro-expanded?  Is the

   DEFMACRO-BLOCK-SCOPE:EXCLUDES-BINDINGS

link telling me this?  That link leads to (among other things)

  http://www.lisp.org/HyperSpec/Issues/iss105-writeup.html

which seems (in part) to be talking about destructuring.

   Looking at the `defmacro' page, and I did not recognize an
explicit statement about how `flet' and `defmacro' interact.  [That
doesn't mean it isn't there; I'm just not recognizing it.]

What I'm really asking is for suggestions on how to read the
hyperspec efficiently [it is big, and I have a poor memory], and how
to find things efficiently.  [There is a lot of terminology that I
haven't yet absorbed.]

================================================================

On a side note, when I do the expansion using `mefull' (i.e
`macroexpand')
rather than `metoo', it doesn't go far enough for me to see the
difference
between the interactions with `let' and with `flet':

  (mefull (list (let ((z 7)) (mac z)) (flet ((mac (z)  (+ z 7))) (mac
100))))
    =>
  (LIST (LET ((Z 7)) (MAC Z)) (FLET ((MAC (Z) (+ Z 7))) (MAC 100)))

I'm guessing that this is some kind of intentional granularity on
the part of `macroexpand', for debugging code.  Are there some
general guidelines on when to use `macroexpand' rather than
`EXT:EXPAND-FORM'?  [I think I understand when to use
`macroexpand-1'.]

     Sincerely, -Jonathan

--
Prof. Jonathan LF King   Mathematics dept, Univ. of Florida
<squash[[at]]math.ufl.edu>,      <http://www.math.ufl.edu/~squash/>
From: Pascal Costanza
Subject: Re: Making my operations context-dependent (RINGS)
Date: 
Message-ID: <5j0ghvF3qivtiU1@mid.individual.net>
·········@math.ufl.edu wrote:

> So the call to `(mac z)' inside of `let' is macro-expanded, and the
> call to `(mac 100)' inside the `flet' is not macro-expanded.
> 
> This makes sense to me; could someone tell me where this is said in
> either the book CLTL2 or at "http://www.lisp.org/HyperSpec/"?

3.1.1.3 and 3.1.2.1.2 in the HyperSpec.

> On a side note, when I do the expansion using `mefull' (i.e
> `macroexpand')
> rather than `metoo', it doesn't go far enough for me to see the
> difference
> between the interactions with `let' and with `flet':
> 
>   (mefull (list (let ((z 7)) (mac z)) (flet ((mac (z)  (+ z 7))) (mac
> 100))))
>     =>
>   (LIST (LET ((Z 7)) (MAC Z)) (FLET ((MAC (Z) (+ Z 7))) (MAC 100)))
> 
> I'm guessing that this is some kind of intentional granularity on
> the part of `macroexpand', for debugging code.  Are there some
> general guidelines on when to use `macroexpand' rather than
> `EXT:EXPAND-FORM'?  [I think I understand when to use
> `macroexpand-1'.]

This is explained in the entry for 'macroexpand: If a form is not a 
macro invocation, then macroexpand just returs that form unchanged.


As a sidenote, you should not do this:

   (defmacro me     (&rest form) `(macroexpand-1   ',@form))
   (defmacro mefull (&rest form) `(macroexpand     ',@form))

But rather:

   (defmacro me     (&rest form &environment env)
     `(macroexpand-1   ',@form env))
   (defmacro mefull (&rest form &environment env)
     `(macroexpand     ',@form env))

Otherwise, these macros may return the wrong expansions because they 
don't see local macro definitions.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Rainer Joswig
Subject: Re: Making my operations context-dependent (RINGS)
Date: 
Message-ID: <joswig-95A5A3.18252521082007@news-europe.giganews.com>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> ·········@math.ufl.edu wrote:
> 
> > So the call to `(mac z)' inside of `let' is macro-expanded, and the
> > call to `(mac 100)' inside the `flet' is not macro-expanded.
> > 
> > This makes sense to me; could someone tell me where this is said in
> > either the book CLTL2 or at "http://www.lisp.org/HyperSpec/"?
> 
> 3.1.1.3 and 3.1.2.1.2 in the HyperSpec.
> 
> > On a side note, when I do the expansion using `mefull' (i.e
> > `macroexpand')
> > rather than `metoo', it doesn't go far enough for me to see the
> > difference
> > between the interactions with `let' and with `flet':
> > 
> >   (mefull (list (let ((z 7)) (mac z)) (flet ((mac (z)  (+ z 7))) (mac
> > 100))))
> >     =>
> >   (LIST (LET ((Z 7)) (MAC Z)) (FLET ((MAC (Z) (+ Z 7))) (MAC 100)))
> > 
> > I'm guessing that this is some kind of intentional granularity on
> > the part of `macroexpand', for debugging code.  Are there some
> > general guidelines on when to use `macroexpand' rather than
> > `EXT:EXPAND-FORM'?  [I think I understand when to use
> > `macroexpand-1'.]
> 
> This is explained in the entry for 'macroexpand: If a form is not a 
> macro invocation, then macroexpand just returs that form unchanged.
> 
> 
> As a sidenote, you should not do this:
> 
>    (defmacro me     (&rest form) `(macroexpand-1   ',@form))
>    (defmacro mefull (&rest form) `(macroexpand     ',@form))
> 
> But rather:
> 
>    (defmacro me     (&rest form &environment env)
>      `(macroexpand-1   ',@form env))
>    (defmacro mefull (&rest form &environment env)
>      `(macroexpand     ',@form env))
> 
> Otherwise, these macros may return the wrong expansions because they 
> don't see local macro definitions.
> 
> 
> Pascal

What is the &rest for anyway?

(macroexpand '(me (foo) (bar) (baz)))

What would above do?

The forms ME* will do nothing to help clear the issue
with MACROEXPAND vs. MACROEXPAND-1.

What is the purpose of writing

   (me (list 'foo)) vs. (macroexpand-1 (list 'foo))

??

-- 
http://lispm.dyndns.org
From: ·········@math.ufl.edu
Subject: Re: Making my operations context-dependent (RINGS)
Date: 
Message-ID: <1189518015.845543.229600@19g2000hsx.googlegroups.com>
Pascal Costanza wrote
>   ...
>   As a sidenote, you should not do this:
>
>      (defmacro me     (&rest form) `(macroexpand-1   ',@form))
>      (defmacro mefull (&rest form) `(macroexpand     ',@form))
>
>   But rather:
>
>      (defmacro me     (&rest form &environment env)
>        `(macroexpand-1   ',@form env))
>      (defmacro mefull (&rest form &environment env)
>        `(macroexpand     ',@form env))
>
>   Otherwise, these macros may return the wrong expansions because they
>   don't see local macro definitions.

Yes, thank you Pascal, I have fixed the macros in my file, and
removed the "&rest", as Rainer Joswig pointed out.

================================================================

On Aug 21, 12:25 pm, Rainer Joswig <······@lisp.de> wrote:

...
>
> What is the purpose of writing
>
>    (me (list 'foo)) vs. (macroexpand-1 (list 'foo))
>
> ??

My poor memory.  When I've been away from a programming
language (in the broad sense) for a while, e.g Maple, TeX,
CSS, I forget what functions/operations are named.  So I alias them
all to a common name, for functions/operations that are
conceptually related, in the different languages.

================

As to my original question about how to make my
ring-operations context dependent, I've written some code
and am now experimenting with it.  I'll post a more precise
version of my question when I've had a chance to see what
the problems are with the current approach.

   Sincerely, -Jonathan King

--
Prof. Jonathan LF King	 Mathematics dept, Univ. of Florida
<squash[[at]]math.ufl.edu>,	 <http://www.math.ufl.edu/~squash/>