From: Toby A. <tob...@pe...> - 2004-03-09 20:52:40
|
I'm wanting to use JScheme as a way to script a J2EE application. I want to be able to run a scheme program that can send a closure to the J2EE application and have it executed by an EJB. The serialization support I submitted is one part of this. The next big hurdle is that I don't want the results of executing a closure in the EJB to taint future executions, and I want to support multiple threads executing independently. Because everything is static, the only way that I can see to have independent interpreters is to play games with class loaders, i.e. to create a new class loader to load the JScheme classes for each interpreter instance. This approach is unsatisfactory to me because I intend to run in a J2EE environment and messing with class loaders is explicitly forbidden by the specification. The performance impact of creating a class loader and loading the classes also troubles me. I propose to make all per-interpreter state (e.g. the dynamic environments, input/output ports) non-static and introduce a per-thread "current interpreter". I see two alternative implementation strategies: 1) Introduce a new class, jsint.Interpreter, that is essentially a de-static-ed version of jsint.Scheme. Then, replace the contents of each static method in jsint.Scheme with delegation to the corresponding method of the current jsint.Interpreter instance. 2) De-static-ify jsint.Scheme and change every static call to Scheme.<something> to Scheme.currentInterpreter().<something>. My questions are: Does anyone see a better or easier way to achieve what I want? Which of the two proposed options would be preferred? Toby. P.S. Yes, I am volunteering to make these changes. |
From: Ken A. <kan...@bb...> - 2004-03-10 00:16:05
|
I think we need to do this carefully. I'd like to hear what Tim has to say. Peter Norvig's original intent was to make jsint.Scheme static "to keep it simple", basically. However, it does cause problems with things like Scheme.out$ So for example if you have multiple using.Active.interactor() windows up only the last one has control of input and output. In fact, i think its fair to say that Peter's design choices were influenced by Java's capabilities at that time, for example , "keep the number of classes small" to minimize applet load times ... With hotspot, we might now make other choices. We could also run JScheme in JDK 1.02 environments, which i think we have finally gone beyond. A third alternative to your proposals might be to make certain things thread local, though i haven't thought about this. Tim came up with the jscheme package in an attempt, i think to clean the original code a little, by using Interfaces for example, and he has an example of a mini JScheme where most of the primitives are written in Scheme. So, we need to consider carefully where your proposed class goes. Please don't use the name Interpreter. JScheme is not interpreted. JScheme code is read, then compiled and then executed. The compiler is both simple and effective (see how those two words almost cancel each other out). Many people avoid Lisp languages because they fear they are interpreted. Also JScheme code can be compiled to Java with Tim's compiler. Evaluator might be a better class name. In fact, maybe this is a time for refactoring. I've been thinking that jsint.Scheme should be broken up. At 09:34 AM 3/10/2004 +1300, Toby Allsopp wrote: >I'm wanting to use JScheme as a way to script a J2EE application. I >want to be able to run a scheme program that can send a closure to the >J2EE application and have it executed by an EJB. The serialization >support I submitted is one part of this. > >The next big hurdle is that I don't want the results of executing a >closure in the EJB to taint future executions, and I want to support >multiple threads executing independently. > >Because everything is static, the only way that I can see to have >independent interpreters is to play games with class loaders, i.e. to >create a new class loader to load the JScheme classes for each >interpreter instance. This approach is unsatisfactory to me because I >intend to run in a J2EE environment and messing with class loaders is >explicitly forbidden by the specification. The performance impact of >creating a class loader and loading the classes also troubles me. > >I propose to make all per-interpreter state (e.g. the dynamic >environments, input/output ports) non-static and introduce a per-thread >"current interpreter". I see two alternative implementation strategies: > >1) Introduce a new class, jsint.Interpreter, that is essentially a >de-static-ed version of jsint.Scheme. Then, replace the contents of >each static method in jsint.Scheme with delegation to the corresponding >method of the current jsint.Interpreter instance. > >2) De-static-ify jsint.Scheme and change every static call to >Scheme.<something> to Scheme.currentInterpreter().<something>. > >My questions are: > >Does anyone see a better or easier way to achieve what I want? > >Which of the two proposed options would be preferred? > >Toby. > >P.S. Yes, I am volunteering to make these changes. > > >------------------------------------------------------- >This SF.Net email is sponsored by: IBM Linux Tutorials >Free Linux tutorial presented by Daniel Robbins, President and CEO of >GenToo technologies. Learn everything from fundamentals to system >administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click >_______________________________________________ >Jscheme-user mailing list >Jsc...@li... >https://lists.sourceforge.net/lists/listinfo/jscheme-user |
From: Toby A. <tob...@pe...> - 2004-03-10 02:04:41
|
On Tue, Mar 09, 2004 at 06:58:35PM -0500, Ken Anderson wrote: > I think we need to do this carefully. I'd like to hear what Tim has > to say. I completely understand. I'm proposing a fairly major change. > Peter Norvig's original intent was to make jsint.Scheme static "to > keep it simple", basically. However, it does cause problems with > things like Scheme.out$ So for example if you have multiple > using.Active.interactor() windows up only the last one has control of > input and output. > > In fact, i think its fair to say that Peter's design choices were > influenced by Java's capabilities at that time, for example , "keep > the number of classes small" to minimize applet load times ... With > hotspot, we might now make other choices. I haven't considered applet loading performance as I'm not interested in using JScheme in an applet. I don't think anything I've done will cause problems in that department. > We could also run JScheme in JDK 1.02 environments, which i think we > have finally gone beyond. In my initial implementation (which I'm testing right now), I've used some JDK 1.2 classes (and possibly some 1.3 ones), but that can probably be worked around if earlier JDK compatibility is required. > A third alternative to your proposals might be to make certain things > thread local, though i haven't thought about this. I don't think there's any choice but to make some things thread local if you want to avoid passing the execution context (perhaps that's a better name than interpreter) into every method. > Tim came up with the jscheme package in an attempt, i think to clean > the original code a little, by using Interfaces for example, and he > has an example of a mini JScheme where most of the primitives are > written in Scheme. So, we need to consider carefully where your > proposed class goes. I must say that I get confused trying to tell the difference between the jsint and jscheme packages. It kind of looks like jscheme is the interface and jsint is the implementation. > Please don't use the name Interpreter. JScheme is not interpreted. > JScheme code is read, then compiled and then executed. The compiler > is both simple and effective (see how those two words almost cancel > each other out). Many people avoid Lisp languages because they fear > they are interpreted. Also JScheme code can be compiled to Java with > Tim's compiler. Evaluator might be a better class name. Hmm, I'll try to stay out of naming arguments, I always end up with a bad name. I suppose I was misled by the comment at the top of Scheme.java :-) > In fact, maybe this is a time for refactoring. I've been thinking > that jsint.Scheme should be broken up. I think some refactoring would help to sort out what this new class should be called. I don't feel close enough to the philosophy behind JScheme to do any really useful refactoring, so I'm going to prepare a patch that does the minimum I can to get it working and hope that it's of use. Toby. |
From: Timothy J. H. <tim...@ma...> - 2004-03-10 03:31:54
|
Hi Toby, Thanks for the serialization/deserialization extension. Its a nice feature to have and I look forward to seeing what we can do with it! As for running multiple independent Scheme's, I think it is a good idea as long as it doesn't make the code too complex (after refactoring...) On Tuesday, March 9, 2004, at 08:46 PM, Toby Allsopp wrote: > On Tue, Mar 09, 2004 at 06:58:35PM -0500, Ken Anderson wrote: >> I think we need to do this carefully. I'd like to hear what Tim has >> to say. > > I completely understand. I'm proposing a fairly major change. It would be nice to be able to create new JScheme instances that could run independently of each other. I would support an effort to do this, provided it doesn't make the implementation too complex and unwieldly (which is unlikely). > >> Peter Norvig's original intent was to make jsint.Scheme static "to >> keep it simple", basically. However, it does cause problems with >> things like Scheme.out$ So for example if you have multiple >> using.Active.interactor() windows up only the last one has control of >> input and output. It might make modules easier to implement as well as we could create a new Scheme instance to load the module into and then copy its exported bindings into the current Scheme instance, so it could actually simplify the code somewhat. >> >> In fact, i think its fair to say that Peter's design choices were >> influenced by Java's capabilities at that time, for example , "keep >> the number of classes small" to minimize applet load times ... With >> hotspot, we might now make other choices. > > I haven't considered applet loading performance as I'm not interested > in using JScheme in an applet. I don't think anything I've done will > cause problems in that department. > >> We could also run JScheme in JDK 1.02 environments, which i think we >> have finally gone beyond. > > In my initial implementation (which I'm testing right now), I've used > some JDK 1.2 classes (and possibly some 1.3 ones), but that can > probably > be worked around if earlier JDK compatibility is required. > >> A third alternative to your proposals might be to make certain things >> thread local, though i haven't thought about this. > > I don't think there's any choice but to make some things thread local > if > you want to avoid passing the execution context (perhaps that's a > better > name than interpreter) into every method. If we make all "execution context variables" thread local, then starting a new thread will be less lightweight. One nice use of threads is to write a simple server that starts a new thread for each incoming socket and then reads from the socket and writes to a common queue (with synchronization as appropriate), I wouldn't want this pattern to be broken. Its true that the nio package makes this use of threads unnecessary, but for small servers it is a nice use of threads.... So, I guess I'd be careful with ThreadLocal variables. Perhaps the default behavior would be to have ThreadLocal variables be initialized to be equal to the parent thread's values, but that resetting a Scheme instance would rebind the ThreadLocal variables to initial values??? > >> Tim came up with the jscheme package in an attempt, i think to clean >> the original code a little, by using Interfaces for example, and he >> has an example of a mini JScheme where most of the primitives are >> written in Scheme. So, we need to consider carefully where your >> proposed class goes. > > I must say that I get confused trying to tell the difference between > the > jsint and jscheme packages. It kind of looks like jscheme is the > interface and jsint is the implementation. Thats essentially right. I wanted jscheme to be the public face of JScheme so that we could change the jsint package radically and not break any programs that relied only on the jscheme package.... With that philosophy, I would suggest leaving the jscheme package mostly unchanged (except for some new functionality procedures in jscheme.REPL) and making most of the patches to jsint.Scheme > >> Please don't use the name Interpreter. JScheme is not interpreted. >> JScheme code is read, then compiled and then executed. The compiler >> is both simple and effective (see how those two words almost cancel >> each other out). Many people avoid Lisp languages because they fear >> they are interpreted. Also JScheme code can be compiled to Java with >> Tim's compiler. Evaluator might be a better class name. > > Hmm, I'll try to stay out of naming arguments, I always end up with a > bad name. I suppose I was misled by the comment at the top of > Scheme.java :-) We do need a better name as Interpreter has a bad connotation maybe just callling it a Scheme instance would do (and we'll need to create a Scheme constructor ....) > >> In fact, maybe this is a time for refactoring. I've been thinking >> that jsint.Scheme should be broken up. > > I think some refactoring would help to sort out what this new class > should be called. I don't feel close enough to the philosophy behind > JScheme to do any really useful refactoring, so I'm going to prepare a > patch that does the minimum I can to get it working and hope that it's > of use. Sounds good. We could refactor after you patch. I have some fairly big JScheme programs that make use of modules, threads, and other features that will provide a good test of whether the patch breaks any older functionality.... We also have the unit tests, but they are not yet comprehensive.... ---Tim--- > > Toby. > > > ------------------------------------------------------- > This SF.Net email is sponsored by: IBM Linux Tutorials > Free Linux tutorial presented by Daniel Robbins, President and CEO of > GenToo technologies. Learn everything from fundamentals to system > administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click > _______________________________________________ > Jscheme-user mailing list > Jsc...@li... > https://lists.sourceforge.net/lists/listinfo/jscheme-user |
From: Michael R H. <bu...@zc...> - 2004-03-10 05:20:48
|
On Tue, 2004-03-09 at 22:14, Timothy John Hickey wrote: > Hi Toby, > It would be nice to be able to create new JScheme instances that > could run independently of each other. I would support an effort > to do this, provided it doesn't make the implementation too complex > and unwieldly (which is unlikely). This could also be potentially very useful for the Eclipse plugin, too. mike -- Michael R Head <bu...@zc...> ZClipse -- OpenSource Eclipse plugins |
From: Ken A. <kan...@bb...> - 2004-03-11 22:29:14
|
OK, since you've got 3 or 4 votes for your proposal, and none against, give it a shot. Why don't you email Tim and i as you do it, for guidence. What i'd do is copy jsint.Scheme into either jsint.REPL or jsint.Evaluator. make most of the static fields non static ... Then get jscheme.REPL to use it rather than jsint.Scheme in main(). Maybe we'll just get rid of Scheme eventually. In fact, remove it and let the compiler tell you where you need to change the code. Scheme.ARGS only makes sense for the first Evaluator. So it should just become a global variable on the Scheme side. What arguments should the constructor take? Probably a DynamicEnvironment at least optionally, but probably also the input, output, and error. Try to avoid setter methods, we want to think functionally when we can. The jscheme.JS class that interfaces from Java to Scheme will need to be changed. For now, have that class create a static final instance to use to keep the code simple. This may be a good tern of events because it may guide us into some good refactorings. For example, i've thought that the REPL (Read Eval Print Loop) could be split up. The E would be an object that too s-expressions and returned their value. It could be attached in the usual REPL way or it could be controled by a GUI that passed commands to it as the user clicked on things and updated the screen accordinly. Also, i once made eval and load replaceable procedures, so for example you could get R5RS macros. But that disappeared when Tim put in DynamicEnvironments. k |
From: Toby A. <tob...@pe...> - 2004-03-14 19:21:04
|
On Thu, Mar 11, 2004 at 05:10:20PM -0500, Ken Anderson wrote: > OK, since you've got 3 or 4 votes for your proposal, and none against, > give it a shot. > > Why don't you email Tim and i as you do it, for guidence. > > What i'd do is copy jsint.Scheme into either jsint.REPL or > jsint.Evaluator. make most of the static fields non static ... Then > get jscheme.REPL to use it rather than jsint.Scheme in main(). Maybe > we'll just get rid of Scheme eventually. In fact, remove it and let > the compiler tell you where you need to change the code. My first cut (which seems to work for my purposes) is basically exactly that. There are a ton of calls to static Scheme methods all through everything, so I think I'll leave those alone as much as possible and just redirect them to the appropriate Evaluator instance. References to static fields in Scheme need to be changed anyway though. In order to determine the appropriate Evaluator instance, I've set up a thread-local stack of them, the interface to which is four methods in JS: Evalutor enter() Evalutor enterNew() void enter(Evaluator) void exit() The expected usage is that any Java code that wants to make calls to JScheme needs to wrap them in: JS.enter(); try { ... } finally { JS.exit(); } The parameterless enter() method will use an existing Evaluator if there is one for the current thread, or will create a new one. The enterNew() method will always create a fresh, new Evaluator instance. New threads get a copy of their parent's Evaluator stack (but the actual Evaluator instances are shared). > Scheme.ARGS only makes sense for the first Evaluator. So it should > just become a global variable on the Scheme side. I don't think ARGS is referred to outside of jsint.Scheme, so it doesn't really make much difference either way. I'd probably prefer it to be an instance field in Evaluator so that you can run multiple scripts that use the args and don't know about each other. > What arguments should the constructor take? Probably a > DynamicEnvironment at least optionally, but probably also the input, > output, and error. Try to avoid setter methods, we want to think > functionally when we can. Do you intend the DynamicEnvironment argument to intialise INTERACTION_ENVIRONMENT? A fair amount of existing code assigns to the input and output fields. Do you mean to replace that with code that instead creates a new Evaluator? > The jscheme.JS class that interfaces from Java to Scheme will need to > be changed. For now, have that class create a static final instance > to use to keep the code simple. I think I've covered this with the methods I propose adding to JS above. > This may be a good tern of events because it may guide us into some > good refactorings. For example, i've thought that the REPL (Read Eval > Print Loop) could be split up. The E would be an object that too > s-expressions and returned their value. It could be attached in the > usual REPL way or it could be controled by a GUI that passed commands > to it as the user clicked on things and updated the screen accordinly. Sounds like a good idea. My changes will get you everything rolled into the E and you can split out the R and the P later if it looks like a good idea. > Also, i once made eval and load replaceable procedures, so for example > you could get R5RS macros. But that disappeared when Tim put in > DynamicEnvironments. Sounds cool :-) I don't know what it means though :-( Toby. |
From: Ken A. <kan...@bb...> - 2004-03-15 22:12:27
|
At 08:20 AM 3/15/2004 +1300, Toby Allsopp wrote: >On Thu, Mar 11, 2004 at 05:10:20PM -0500, Ken Anderson wrote: >> OK, since you've got 3 or 4 votes for your proposal, and none against, >> give it a shot. >> >> Why don't you email Tim and i as you do it, for guidence. >> >> What i'd do is copy jsint.Scheme into either jsint.REPL or >> jsint.Evaluator. make most of the static fields non static ... Then >> get jscheme.REPL to use it rather than jsint.Scheme in main(). Maybe >> we'll just get rid of Scheme eventually. In fact, remove it and let >> the compiler tell you where you need to change the code. > >My first cut (which seems to work for my purposes) is basically exactly >that. There are a ton of calls to static Scheme methods all through >everything, so I think I'll leave those alone as much as possible and >just redirect them to the appropriate Evaluator instance. References to >static fields in Scheme need to be changed anyway though. right. >In order to determine the appropriate Evaluator instance, I've set up a >thread-local stack of them, the interface to which is four methods in >JS: > >Evalutor enter() >Evalutor enterNew() >void enter(Evaluator) >void exit() > >The expected usage is that any Java code that wants to make calls to >JScheme needs to wrap them in: > > JS.enter(); > try { > ... > } finally { > JS.exit(); > } > >The parameterless enter() method will use an existing Evaluator if there >is one for the current thread, or will create a new one. The enterNew() >method will always create a fresh, new Evaluator instance. > >New threads get a copy of their parent's Evaluator stack (but the actual >Evaluator instances are shared). At first look, i don't like this. I don't like having to do a try/finally in Java to get something done for me by Scheme. My first suggestion of leaving the JS interface alone is probably wrong. The way JS is typically used is you define a Java class that loads some Scheme code as a static init and then defines some Java methods that do JS.call() to get the behavior done for it. So putting a try/finally around one line is too costly. You may also want to turn an s-expression as a string into an Object. Maybe, JS should just be a wrapper around an Evaluator and a class or a Thread that wanted Scheme evaluated would just set up the Scheme environment it want the Evaluator to have and call the appropriate JS functions. >> Scheme.ARGS only makes sense for the first Evaluator. So it should >> just become a global variable on the Scheme side. > >I don't think ARGS is referred to outside of jsint.Scheme, so it doesn't >really make much difference either way. I'd probably prefer it to be an >instance field in Evaluator so that you can run multiple scripts that >use the args and don't know about each other. ARGS is there to allow Scheme code to see what arguments were passed in. Any piece of code might want that, but it certainly doesn't make much sense in a "container environment". So maybe ARGS should just be a global variable in the initial environment so it can be used by any Evaluator down stream, was my initial thought. However, Looking at all the arguments doesn't make much sense because the arguments are processed by Scheme in a particular way and you can use the -main option to take over interpreting the rest of the arguments, as in src/using/command.scm for example. So, my proposal now is to get rid of ARGS. In Common Lisp, proposals were named like this: get-rid-of-args. >> What arguments should the constructor take? Probably a >> DynamicEnvironment at least optionally, but probably also the input, >> output, and error. Try to avoid setter methods, we want to think >> functionally when we can. > >Do you intend the DynamicEnvironment argument to intialise >INTERACTION_ENVIRONMENT? The idea was that evaluators could somehow share environments so either an evaluator could load specific code, as you might want in scheme-server-pages or could share code that was only loaded once, which you might want if you're a server spawing a new evalutor for each thread, but they all have the same behavior. >A fair amount of existing code assigns to the input and output fields. >Do you mean to replace that with code that instead creates a new >Evaluator? No, this code must bechanged into nonstatic calls. >> The jscheme.JS class that interfaces from Java to Scheme will need to >> be changed. For now, have that class create a static final instance >> to use to keep the code simple. > >I think I've covered this with the methods I propose adding to JS above. > >> This may be a good tern of events because it may guide us into some >> good refactorings. For example, i've thought that the REPL (Read Eval >> Print Loop) could be split up. The E would be an object that too >> s-expressions and returned their value. It could be attached in the >> usual REPL way or it could be controled by a GUI that passed commands >> to it as the user clicked on things and updated the screen accordinly. > >Sounds like a good idea. My changes will get you everything rolled into >the E and you can split out the R and the P later if it looks like a >good idea. > >> Also, i once made eval and load replaceable procedures, so for example >> you could get R5RS macros. But that disappeared when Tim put in >> DynamicEnvironments. >Sounds cool :-) I don't know what it means though :-( (load) and (eval) are Scheme procedures that have fixed semantics written in Java. By redefining them, you can change the semantics for example by adding a more powerful macro system than Scheme has by default. Or you could play with new evaluation models as in Paul Graham's ARC language http://www.paulgraham.com/arc.html so you could do things like (define v #(0 1 2 3)) (v 1) -> 1; apply a vector. or even (1 v) -> 1; apply a number to a vector. |
From: Toby A. <tob...@pe...> - 2004-03-16 00:21:55
|
On Mon, Mar 15, 2004 at 05:12:00PM -0500, Ken Anderson wrote: > At 08:20 AM 3/15/2004 +1300, Toby Allsopp wrote: > > The expected usage is that any Java code that wants to make calls to > > JScheme needs to wrap them in: > > > > JS.enter(); > > try { > > ... > > } finally { > > JS.exit(); > > } > > At first look, i don't like this. I don't like having to do a > try/finally in Java to get something done for me by Scheme. My first > suggestion of leaving the JS interface alone is probably wrong. > > The way JS is typically used is you define a Java class that loads > some Scheme code as a static init and then defines some Java methods > that do JS.call() to get the behavior done for it. So putting a > try/finally around one line is too costly. Okay, this usage suggests that you probably want to create an instance of JS and call non-static methods on it. > You may also want to turn an s-expression as a string into an Object. > Maybe, JS should just be a wrapper around an Evaluator and a class or > a Thread that wanted Scheme evaluated would just set up the Scheme > environment it want the Evaluator to have and call the appropriate JS > functions. I'm not sure I follow what you mean there. My interpretation is to basically make all JS methods non-static and provide a constructor that takes an evaluator as an argument (and one that doesn't). > > I don't think ARGS is referred to outside of jsint.Scheme, so it > > doesn't really make much difference either way. I'd probably prefer > > it to be an instance field in Evaluator so that you can run multiple > > scripts that use the args and don't know about each other. > > ARGS is there to allow Scheme code to see what arguments were passed > in. > Any piece of code might want that, but it certainly doesn't make much > sense in a "container environment". So maybe ARGS should just be a > global variable in the initial environment so it can be used by any > Evaluator down stream, was my initial thought. However, Looking at > all the arguments doesn't make much sense because the arguments are > processed by Scheme in a particular way and you can use the -main > option to take over interpreting the rest of the arguments, as in > src/using/command.scm for example. So, my proposal now is to get rid > of ARGS. In Common Lisp, proposals were named like this: > get-rid-of-args. It turns out that it doesn't bother me either way :-). I'll probably leave it with the easiest to implement semantics and let it be removed or retained by someone who has an interest in it. > > > What arguments should the constructor take? Probably a > > > DynamicEnvironment at least optionally, but probably also the > > > input, output, and error. Try to avoid setter methods, we want to > > > think functionally when we can. > > > > Do you intend the DynamicEnvironment argument to intialise > > INTERACTION_ENVIRONMENT? > > The idea was that evaluators could somehow share environments so > either an evaluator could load specific code, as you might want in > scheme-server-pages or could share code that was only loaded once, > which you might want if you're a server spawing a new evalutor for > each thread, but they all have the same behavior. Oh, I see. I'd expect the threads to just share an evaluator. There's not much difference, but it does make more sense to just share the environment if that's what you want. > > A fair amount of existing code assigns to the input and output > > fields. Do you mean to replace that with code that instead creates > > a new Evaluator? > > No, this code must bechanged into nonstatic calls. This is what I currently have, I think. Once we have the try...finally issue above sorted out I'll post the code and we can get into specifics. > > > Also, i once made eval and load replaceable procedures, so for > > > example you could get R5RS macros. But that disappeared when Tim > > > put in DynamicEnvironments. > > > > Sounds cool :-) I don't know what it means though :-( > > (load) and (eval) are Scheme procedures that have fixed semantics > written in Java. By redefining them, you can change the semantics for > example by adding a more powerful macro system than Scheme has by > default. Or you could play with new evaluation models as in Paul > Graham's ARC language > http://www.paulgraham.com/arc.html > > so you could do things like > > (define v #(0 1 2 3)) > (v 1) -> 1; apply a vector. > > or even > (1 v) -> 1; apply a number to a vector. Ok, this is outside the scope of what I'm thinking about, I think :-) Toby. |