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

Okay, looks good.

As an aside: maybe it's better to make the primitives really, really primitive?

Basically we define separate %n+ for adding two fixnums, %f+ for adding two flonums, %fn+ for adding a flonum and a fixnum (in that order) and, %nf+ for adding a fixnum and a flonum (in that order).

Then we can write + in lib-ac.scm.arc as:

  (set +
    (fn rest
      ($+ rest)))
  (set $+
    (fn (args)
      (if args
          (if (%cdr args)
              ($sub+ (%car args) (%cdr args))
              (%car args))
          0)))
  (set $sub+
    (fn (accum rest)
      (if rest
          ((fn (val rest)
             (if (%is (%type accum) 'int)
                 (if (%is (%type val) 'int)
                     ($sub+ (%n+ accum val) rest)
                     (if (%is (%type val) 'num)
                         ($sub+ (%nf+ accum val) rest)
                         ; raise exception
                         ()))
                 (if (%is (%type accum) 'num)
                     (if (%is (%type val) 'int)
                         ($sub+ (%fn+ accum val) rest)
                         (if (%is (%type val) 'num)
                             ($sub+ (%f+ accum val) rest)
                             ; raise exception
                             ()))
                     ; raise exception
                     ())))
            (%car rest) (%cdr rest))
          accum)))
As for macros: Hmm. You see... Look, up in the sky! Is it a bird? A plane? Superman? Nothing? Oh, what were we talking about again? ^^ LOL

Okay now serious: currently I'm blocked with creating a "protected" eval for macros. Programmer's block. The bit blocking me is the destructuring thing. Erk.



1 point by sacado 5839 days ago | link

I think you're right for primitives. I asked pg the same question a few time ago, he answered he didn't know yet. Anyway, for an optimizing compiler, we will need these (as in : "hmmm, n can only hold a fixnum, let's translate this heavy '+ in a lightweight '%n+ !")

Now, macros. I tried to think about it yesterday, and I don't really understand why you need this protected mode. I mean, macros have to be defined (globally) before they are called and treated as such. Since you can already identify all the globals (and since a macro is a global thing annotated by 'mac), it should be easy to

- make a list of all the symbols holding a macro at a given moment in the code

- explore all the sexprs to see if one of those symbols is the first element of any sublist

- if it is to, make the transformation

- do it again until nothing changes anymore

Am I missing something obvious ?

-----

3 points by almkglor 5838 days ago | link

  (do
    (= xe 0)
    (mac somethingstupid ()
      (= xe (+ xe 1))
      `(prn "something stupid" ,xe)))

... and 'xe is a function in....?

-----

2 points by sacado 5837 days ago | link

OK , so I was missing something obvious :)

If I understand well, we have to interpret the code as we compile it (as a macro's body is executed when a function is defined/compiled, not when executed) ? To me, macros were something translating a piece of code into another one, period. But that's not always the case as your example shows. If someone writes

  (mac foo
    (prn "blah"))

  (def bar (n)
    (foo) (* n 2))
That means we have to display "blah" on compile time, right ? Hmm, that's much harder than I thought... It really means implementing an arc interpreter in arc (the way the official one is written in mzscheme), with for example prepending all the interpreted names with _ to distinguish them from the compiler's names...

Ok, I think I'm starting to realy get it ; or am I still missing an even trickier issue ?

-----

2 points by almkglor 5837 days ago | link

That is about it. ^^ However my current implementation uses tables as environments for the function. Keys in the table are symbols for the variable names in that environment. A "parent" string key accesses the environment's parent.

The global environment is shadowed by a table; when this table is accessed, if a table entry does not exist, we look it up in the real environment using 'eval (!!) and retain a copy. This allows the macro to use stuff like 'map.

However there is still a leak here: if the real global-level environment has a function that modifies a global, it will modify a different global variable from the one that is visible to the macro. This shouldn't happen anyway: we should really avoid using globals in utility functions ^^.

-----