Giter VIP home page Giter VIP logo

Comments (16)

kelleyvanevert avatar kelleyvanevert commented on June 3, 2024 1

Oh, wait, I get it. "Inlining" as in what compilers to with simple functions :)

from ganja.js.

kelleyvanevert avatar kelleyvanevert commented on June 3, 2024 1

Yes, well of course that works, but that's hardly an API..

from ganja.js.

enkimute avatar enkimute commented on June 3, 2024 1

yes. easy-peasy.

it's just string magic - no logic going on there ;)

from ganja.js.

kelleyvanevert avatar kelleyvanevert commented on June 3, 2024 1

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.

enkimute avatar enkimute commented on June 3, 2024

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.

enkimute avatar enkimute commented on June 3, 2024

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.

kelleyvanevert avatar kelleyvanevert commented on June 3, 2024

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.

enkimute avatar enkimute commented on June 3, 2024

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.

kelleyvanevert avatar kelleyvanevert commented on June 3, 2024

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.

enkimute avatar enkimute commented on June 3, 2024

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.

kelleyvanevert avatar kelleyvanevert commented on June 3, 2024

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.

enkimute avatar enkimute commented on June 3, 2024

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.

kelleyvanevert avatar kelleyvanevert commented on June 3, 2024

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.

kelleyvanevert avatar kelleyvanevert commented on June 3, 2024

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.

enkimute avatar enkimute commented on June 3, 2024

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.

enkimute avatar enkimute commented on June 3, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.