I'm trying to implement mal on ciforth
https://github.com/kanaka/mal
Amounts to implementing a dialect of lisp using a dialect of Forth.
In step 8 I encounter the following:
-Add a new attribute is_macro to mal function types. This should
default to false.
Am I mistaken or is this the familiar immediate flag added to
Forth definitions?
- Add a new special form defmacro!. This is very similar to the def!
form, but before the evaluated value (mal function) is set in the
environment, the is_macro attribute should be set to true.
Much like colon definitions, later to be modified by IMMEDIATE to add
that behaviour.
- Add a macroexpand function: This function takes arguments ast and env.
It calls is_macro_call with ast and env and loops while that condition
is true.
How is this different from executing an immediate definition in
the middle of deferring an action? The only difference seems
to be that Forth does this much cleaner and with less caveats.
First and foremost it is far easier to keep track of arguments.
They reside on the stack.
Am I the first to notice this? Chuck Moore was a student of McCarthy.
Perhaps he invented Forth as a simpler version of lisp.
On 2023-07-07, albert@cherry.(none) (albert) <albert@cherry> wrote:<SNIP>
I'm trying to implement mal on ciforth
https://github.com/kanaka/mal
Amounts to implementing a dialect of lisp using a dialect of Forth.
If you're writing code in Forth to make that work, then of course
that is your problem.
If you're making a Forth from scratch, you have to implement
several stacks yourself.
If you're making a Lisp from scratch, you have to implement
environments.
The simplest possible implementation of environments is stack-like.
The environment is the head of an association list, which looks like
this: ((b . 1) (a . 2)) for an environment which contains two
variables a and b bound to values 1 and 2.
A new binding is created with cons:
(cons (cons 'c 3) previous-env)
In some Lisps like Common Lisp, there is an acons for this:
(acons 'c 3 previous-env)
a new env is returned which looks like ((c . 3) (b . 1) (a . 2)).
The new environment doesn't clobber the old one; the environment
is a local variable in a recursive interpreter, passed around through
its recursion.
That's a reference model for a lexically scoped Lisp that came
into the Lisp culture mainly via the Scheme influence.
A lexically scoped Lisp doesn't have to reveal to the programs
the detailed representation of environments. Unless a special
escape hatch is provided for it, programs don't see the hidden
"env" variable. This is a good thing because it allows programs
to be compiled. Compiled code uses a radically different
representation of the environment.
KasGroetjes Albert
I'm trying to implement mal on ciforth
https://github.com/kanaka/mal
Amounts to implementing a dialect of lisp using a dialect of Forth.
In step 8 I encounter the following:
-Add a new attribute is_macro to mal function types. This should
default to false.
Am I mistaken or is this the familiar immediate flag added to
Forth definitions?
- Add a new special form defmacro!. This is very similar to the def!
form, but before the evaluated value (mal function) is set in the environment, the is_macro attribute should be set to true.
Much like colon definitions, later to be modified by IMMEDIATE to add
that behaviour.
- Add a macroexpand function: This function takes arguments ast and env.
It calls is_macro_call with ast and env and loops while that condition
is true. Inside the loop, the first element of the ast list (a
symbol), is looked up in the environment to get the macro function.
This macro function is then called/applied with the rest of the ast
elements (2nd through the last) as arguments. The return value of the
macro call becomes the new value of ast. When the loop completes
because ast no longer represents a macro call, the current value of
ast is returned.
How is this different from executing an immediate definition in
the middle of deferring an action? The only difference seems
to be that Forth does this much cleaner and with less caveats.
First and foremost it is far easier to keep track of arguments.
They reside on the stack.
Am I the first to notice this? Chuck Moore was a student of McCarthy.
Perhaps he invented Forth as a simpler version of lisp.
Groetjes Albert
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the hide of the bear until you shot it. Better one bird in the hand than ten in the air. First gain is a cat spinning. - the Wise from Antrim -
To me, in the Forth context, MACRO means to copy the code in the MACRO's definition into the word, as opposed to compiling a call to the word.
I support MACROs in my dialect for 2 reasons; I call them INLINE.
(1) it improves the performance by removing the overhead of the call
(2) it can save memory ... my implementation is byte-coded, so on a 64-bit system, a call takes 9 bytes.
- Chris
On Wednesday, 12 July 2023 at 14:03:25 UTC+1, ccur...@gmail.com wrote:
To me, in the Forth context, MACRO means to copy the code in theMACRO's definition into the word, as opposed to compiling a call to the
word.
64-bit system, a call takes 9 bytes.
I support MACROs in my dialect for 2 reasons; I call them INLINE.
(1) it improves the performance by removing the overhead of the call
(2) it can save memory ... my implementation is byte-coded, so on a
- Chris
In forth definitions are compiled or executed. Forth works with words
and lisp works with forms.
I can imagine an example where code is in a string which is then
inserted into another string before
being compiled or writing a special word that inserts postpone(s) into
definition.
I could never get the second one working it was too complicated for me.
The first one worked but I
didnt have a usecase for it.
How did you get your macro to copy code from a macro into a word ?
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 300 |
Nodes: | 16 (2 / 14) |
Uptime: | 34:57:02 |
Calls: | 6,707 |
Files: | 12,239 |
Messages: | 5,353,385 |