Comments (16)
Oh, wait, I get it. "Inlining" as in what compilers to with simple functions :)
from ganja.js.
Yes, well of course that works, but that's hardly an API..
from ganja.js.
yes. easy-peasy.
it's just string magic - no logic going on there ;)
from ganja.js.
Another road to take, would be to go less "it's just code" and more "register a collection of functions in a defined space", say something like:
const A = Algebra(4,1);
const scope = A.scope(); // or .namespace()
scope.ei = scope.def(() => 1e4 + 1e5)();
scope.f = scope.def(() => ei + 5);
Not really the original goal you had in mind, but at least it has a clear and clean API and the other advantages are kept. Of course you'd implement it something like:
scope.def = f => return eval("(() => with(scope) { return " + magic(f.toString()) + "; })()");
from ganja.js.
Hmm .. I've used the same workaround but you've made me wonder what scope eval runs in .. I'll have to play around and see if any of the create function constructs in js may do the trick .. tbc ..
Another workaround would be to have a specific namespace that is only used to specify scoping but doesn't perform substitution .. i.e.
Algebra().namespace(()=>{
var a;
Algebra(3,0,1,()=>{
var c=1+1e1; // substituted.
console.log(a,c); // can access scope
});
var c=1+1; // not substituted
});
Obviously if a precompile step is an option it would be easy to tweak ganja to simply output the processed result as a string which would retain lexical scoping.
I've been playing around with that idea since I want to try the closure compiler and perhaps even prepack to see how it could optimize GA code.
from ganja.js.
Actually that namespace idea is not to bad .. I may give that a go .. it would basically process the entire scope, only substitute the algebra calls it finds and then finally run the entire thing ..
from ganja.js.
The namespace is clever :)
As far as I can see, you really can't beat lexical scoping. For all the inflection and other crazy things you can do with javascript, I don't think there's a way to inject/mess around with the scope a function runs in. (The best I can think of is with
, but even then you need an object to start with.) The namespace option might best the best shot.
from ganja.js.
Well .. never say never .. hows about this :
It's a bit of a hack I'll admit - but - works in the current version ;)
var aaa=3;
eval(Algebra(2,0,1,()=>(()=>{
console.log(aaa);
}).toString()))();
the inline function once had an option to return a string instead of a bound function .. I'll add that back in and that will make this a lot cleaner ..
from ganja.js.
If you break it down, there's the following to the inline feature:
- It's essentially just string logic, so there's no magic going on there, but:
- using normal javascript code enables code editors to do their static analysis. This is the only thing to it that distinguishes the feature from a regular expressions parser/evaluator, like say in the math.js library.
Your last eval
example does retain this value, but it's a sore compromise.
from ganja.js.
Hmm .. that makes it a lot more top heavy tho, the current scope is shared over several calls to inline so you could use this :
const A = Algebra(4,1);
A.inline(()=>this.ei = 1e4 + 1e5)();
A.inline(()=>this.ei + 5)();
Also, in your suggestion referencing ei would not be trivial to substitute (I'd have to explicitely forward to global scope in case of undefined .. ) - so it would have to be scope.ei in your example to, similar to this.ei in mine.
from ganja.js.
Not entirely sure what you mean with forwarding to global scope and undefined, but I'd imagine you want to substitute the operators (and basis vectors) with DSL functions in your string magic, instead of the variables/subexpressions themselves, if that's what you're now doing. I.e. if replace x + y
with plus(x, y)
and have plus
do appropriate lifting etc, instead of with <replaced>.plus(<replaced>)
. Does that make sense? The string magic should only delegate the actual operator application instead of handle the overloading logic itself. The helpers that eventually execute the operator, choose dynamically whether the objects in question need lifting.
Didn't know that the scope was shared though (didn't really think about it actually), so that's nice :)
from ganja.js.
I'm currently doing exactly that (only translating the operators) - which would not cover your example (since you reference ei without explicit scope in your last line, and ganja.js is not touching identifiers - ei would be undefined there)
i.e. your example would have to read :
const A = Algebra(4,1);
const scope = A.scope("scopename"); // or .namespace()
scope.ei = scope.def(() => 1e4 + 1e5)();
scope.f = scope.def(() => scopename.ei + 5);
You wouldn't be able to do it with just ei with the current translator.
from ganja.js.
Technically speaking, this works, because of the with
trick:
{
// library implementation
const magic = str => str.replace('5', '6');
const scope = {
def: f => eval(`(() => { with(scope) { return (${magic(f.toString())}); } })()`),
};
// user api
scope.ei = scope.def(() => 4+5)();
scope.f = scope.def(n => ei+10);
console.log("ei=",scope.ei,"f=",scope.f()); // ei=10, f=20
}
But such an api would really only be logical to emulate "normal lexical scope" if the variable ei
in the definition of f
would in normal lexical scoping refer to something, which now it doesn't. You'd have to redundantly write
const ei = scope.ei = scope.def(() => 4+5)();
scope.f = scope.def(n => ei+10);
and maybe the api could encourage this way of coding by strictly separating the two namings to something just javascript and something string-logic:
const ei = scope.def("ei", () => 4+5)();
const f = scope.def("f", n => ei+10);
...but you're still stuck with the typical "register things" ugly redundancy of double names.
from ganja.js.
The one time I saw this kind of lexical scoping emulated through scope objects and with
work real nice, was in the setting of html templating for the mvvm library Knockout.js. You'd write the plain html:
<ul data-bind="foreach: platonic_solids">
<li><strong data-bind="text: name"></strong> (faces: <span data-bind="text: numFaces"></span>)</li>
</ul>
to template objects such as { platonic_solids: [ { name: 'Tetrahedron', numFaces: 4 }, ... ] }
But, the difference is that this templating 'DSL' didn't 'mix' with normal javasctipt code, whereas your inline functions do.
You lose lexical scoping if you let the library do the eval
, and could only replace it with some kind of object-lookup, either throug with kind of with
-emulation, or just telling the programmer to store variables in this
.
from ganja.js.
yes - that pretty much wraps it up. So I'll go for splitting the scope from the translation, with an explicit, optional syntax. Everything stays the way it is but if you run into scoping problems you can wrap your entire context in an Algebra.scope(()=>{})
that moves the translator one level up so to speak.
I'll try to find some time this week to give that a go.
from ganja.js.
In the latest ganja.js, the inline function has been upgraded so it can also be used as a template string function. This creates an in for the scoping problem as you could now write :
var C = Algebra(0,1).inline, // complex numbers as template string function
a = 6; // variable in outside scope
C`console.log(1e1+${a})` // complex function using variable from outside scope
For now, I'll consider this a workable setup and close this issue.
from ganja.js.
Related Issues (20)
- Straightforward way to get current camera view/projection matrix? HOT 1
- Add TypeScript support HOT 6
- Calling Inverse raises error in 0 dimensions
- The code is unclear HOT 1
- Support WebVR HOT 3
- Feature Request for {data:cubeF, transform:1+1e0}
- Feature request: larger viewport in (2,0,1)*
- Having troubles including classes within Algebra() scope HOT 4
- division by zero inconsistent with IEEE 754 standard
- Table at section "Ganja ingredients and syntax." should have a row for inner product operator "|" HOT 1
- Nested reactivity broken with OpenGL HOT 1
- Feature Request: General Inverse creation in the code generator HOT 1
- I found a reference that might be useful to include in the documentation
- Why doesn't ganja.js follow the right hand rule?
- Inline parser regression: character choking
- Offsets out of bounds for Quaternion addition
- [inline] Support for Object Methods
- Long SVG lines bug in Chrome
- Dual of 1 returns false
- Can't drag points on iPad Pro 2021
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ganja.js.