Arc Forumnew | comments | leaders | submitlogin
2 points by almkglor 5948 days ago | link | parent

> What I now think is something very similar to what you've been saying, except I still think it would be cool if this could be a method of managing general environments, instead of just modules. I don't know if that was what you were thinking, or not; it's more of an implementation detail.

Yes, it would definitely be cool to access the environment. For one, it would make serializing functions possible: aside from giving accessors to the environment and to the function code, you can give constructors for functions that accept a serializable environment and a serializable function code.

> If it made any sense, I would use the syntax env.sym, so that it can be evaluated to figure out what type it is.

Typical 'isa pattern:

  (isa foo 'cons)
Translating to module.sym form:

  (isa foo 'arc.cons)
.... except that arc.cons == (arc cons) and you'd be comparing the type to the unevaluated (arc cons), because of the ' mark.

With <arc>cons syntax, the "<" and ">" characters are simply passed directly, i.e. <arc>cons is just a single symbol.



1 point by shader 5947 days ago | link

Is there any reasonable way to prevent the dot from being interpreted there? Or alternatively, evaluate the whole statement?

And how is the isa statement going to be updated to work independent of which module it's running in? Does each module type all of it's objects that way from the beginning, or were you going to have the interpreter do something fancy?

-----

1 point by almkglor 5946 days ago | link

> Is there any reasonable way to prevent the dot from being interpreted there? Or alternatively, evaluate the whole statement?

First things first. We want to make the type arc.cons readable, don't we? So if say 'arc here is a macro, it will expand to a symbol, which is basically "the symbol for cons in the arc package".

Now that symbol can't be a 'uniq symbol, since those are perfectly unreadable.

What we could do is....... oh, just make up a symbol from the package name and the given symbol. Like, say...... <arc>cons. The choice of <> is completely arbitrary.

Now.... if (arc cons) is a macro that expands to <arc>cons, why go through the macro?

> And how is the isa statement going to be updated to work independent of which module it's running in? Does each module type all of it's objects that way from the beginning, or were you going to have the interpreter do something fancy?

Something fancy, of course. Specifically it hinges on the bit about the "contexter". Remember that in my proposal I proposed adding an additional step after the reader, viz. the contexter.

Basically the contexter holds the current package and it puts any unpackaged symbols it finds into the mapping for the current package.

So for example we have:

  (in-package foo)
  (using <arc>v3)
  (interface <foo>v1
    make-a-foo foo-type is-a-foo)
  (def make-a-foo (x)
    (annotate 'foo-type x))
  (def is-a-foo (x)
    (isa x 'foo-type))
Now the contexter goes through it and maintains hidden state. This state is not shared and is not assured of being shared across threads (it might, it might not, implementer's call - for safety just assume it doesn't)

Initially the contexter has the package "User".

It encounters:

  (in-package foo)
This changes its internal package to "foo". This (presumably) newly-created package is given a set of default mappings, corresponding to the arc axioms: fn => <axiom>fn, quote => <axiom>quote, if => <axiom>if, etc. The contexter then returns:

  t
The t is evaluated and returns.... t.

Then it accepts:

  (using <arc>v3)
This causes the contexter to look for a "v3" interface in the "arc" package. On finding them, it creates default mappings; among them are:

  def => <arc>def
  isa => <arc>isa
  annotate => <arc>annotate
  ...etc.
Upon accepting this and setting up the "foo" package to use <arc>v3 interface, it again returns:

  t
Then it accepts:

  (interface <foo>v1
    make-a-foo foo-type is-a-foo)
This causes the contexter to create a new interface for the package "foo", named "v1". This interface is composed of <foo>make-a-foo, <foo>foo-type, and <foo>is-a-foo.

After creating the interface, it then returns:

  t
Then it accepts:

  (def make-a-foo (x)
    (annotate 'foo-type x))
Since it isn't one of the special contexter forms, it simply uses the mapping of the current package - specifically the package foo - and returns the form:

  (<arc>def <foo>make-a-foo (<foo>x)
    (<arc>annotate '<foo>foo-type <foo>x))
Notice how x is implicitly mapped into the package foo; basically any unpackaged symbol which doesn't have a mapping in a package is automatically given to that package.

Then the contexter accepts:

  (def is-a-foo (x)
    (isa x 'foo-type))
Which is returned as:

  (<arc>def <foo>is-a-foo (<foo>x)
    (<arc>isa <foo>x '<foo>foo-type))
So there: the contexter automagically inserts packages.

-----

1 point by shader 5944 days ago | link

See, I told you you'd convince me to come around to your way of thinking, once I'd asked enough questions to find out the reasons for the choices you've made.

So, how hard is it to take what you've made so far, and generalize it to work with any kind of environment, and not just packages? So, things like destructuring functions, naming environments, passing them around, etc. Would this allow us to avoid shadowing variables by naming which level they came from explicitly?

Also, if I type in the symbol '<arc>bar, will the contexter read that and presume I'm looking for the bar in arc, or will it rename it <foo><arc>bar? And which is better?

If it's the latter, how would you propose we directly reference a particular environment? Would that be pack.sym, like I had thought earlier?

-----

1 point by almkglor 5944 days ago | link

> So, how hard is it to take what you've made so far, and generalize it to work with any kind of environment, and not just packages?

Hmm. Well, if you want to be technical about things, one Neat Thing (TM) that most compilers of lexical-scope languages (like Scheme and much of CL, as well as Arc) do is "local renaming". Basically, suppose you have the following code:

  (fn (x)
    (let x (+ x 1)
      x))
This is transformed (say by arc2c) into:

  (fn (x@1)
    (let x@2 (+ x@1 1)
      x@2))
Note that the renaming could actually be made more decent, i.e. something readable. For example, in theory the renaming could be done more like:

  (fn (<fn>x)
    (let <fn/let>x (+ <fn>x 1)
      <fn/let>x))
^^

In fact I am reasonably sure that Scheme's hygienic macros work after local renaming, unlike CL's which work before renaming. You'll probably have to refer to some rather turgid papers though IMO, and decompressing turgid papers is always hard ^^.

> Also, if I type in the symbol '<arc>bar, will the contexter read that and presume I'm looking for the bar in arc, or will it rename it <foo><arc>bar? And which is better?

Well, since packages are constrained to be nonhierarchical, <arc>bar is considered already packaged and the contexter will ignore them. The contexter will add context only to unpackaged symbols.

-----

1 point by rincewind 5945 days ago | link

If I write this into the foo-package-file:

   (let list '(this is a test case)
       (all is-a-foo (map make-a-foo list)))
   
would list be read as <foo>list or <arc>list? Should the expression

   (sym "make-a-foo")
evaluate to <foo>make-a-foo?

-----

2 points by almkglor 5944 days ago | link

> If I write this into the foo-package-file: ....

Assuming you mean in the same file with the example foo package:

  (<arc>let <arc>list (<axiom>quote (<arc>this <arc>is <foo>a <foo>test <arc>case))
    (<arc>all <foo>is-a-foo (<arc>map <foo>make-a-foo <arc>list)))
> Should the expression ....

No, it evaluates to the unpackaged symbol 'make-a-foo.

-----