• IMMEDIATE and def_macro

    From none) (albert@21:1/5 to All on Fri Jul 7 14:15:27 2023
    XPost: comp.lang.lisp

    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 -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to albert@cherry on Fri Jul 7 17:57:16 2023
    XPost: comp.lang.lisp

    On 2023-07-07, albert@cherry.(none) (albert) <albert@cherry> wrote:
    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?

    It may be similar. Macros are invoked during expansion.
    Code can be expanded without being executed immediately. Or
    at all. For instance

    ;; function is only defined, not called; but macro is called
    (defun foo ()
    (macro ..))

    ;; macro likely called in spite of being dead code.
    ;; (unless expander handles trivial dead code elimination cases).
    (if nil
    (macro ...))

    - 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.

    There amy be some similarities, but that doesn't necessarily mean
    you can solve the MAL task by mapping macros directly to IMMEDIATE
    words.

    - 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.

    The user of the macro system doesn't have any problem with argument
    tracking; arguments nicely appear as lexically scoped identifiers,
    bound on entry into the function.

    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.

    Am I the first to notice this? Chuck Moore was a student of McCarthy.
    Perhaps he invented Forth as a simpler version of lisp.

    Even assembly languages have actions that are done now, while
    assembling the code, and not at run-time.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From none) (albert@21:1/5 to 864-117-4973@kylheku.com on Sat Jul 8 10:05:06 2023
    XPost: comp.lang.lisp

    In article <20230707102938.23@kylheku.com>,
    Kaz Kylheku <864-117-4973@kylheku.com> wrote:
    On 2023-07-07, albert@cherry.(none) (albert) <albert@cherry> wrote:
    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.

    <SNIP>
    (much appreciated insight)


    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.

    That is available in Forth under the name wordlist.
    There is a structure name VOCABULARY that have names and
    traditionally are linked among themselves, that can be used
    to point to outer environments.


    A new binding is created with cons:

    (cons (cons 'c 3) previous-env)

    In my forth this is implemented as
    [``set'' and ``get'' is the name prescribed by mal.]
    \ Add symbol value to the current.
    : set >R $, R@ >NFA ! R> CURRENT @ LINK ;
    Note that each of these components are available in the Forth
    core.
    Finding a name through a recursive environments is done by
    \ For sc env-wid , return item . or throw. Follow outer links.
    : get
    BEGIN DUP >R (FIND) DUP 0= WHILE
    DROP R> WID>VFA @ DUP 0= 8010 ?ERROR
    >WID REPEAT
    NIP NIP RDROP ;
    Likewise each of the components are present in the Forth core.
    Not necessarily ISO standard words, but language components
    needed to implement Forth that are repurposed.


    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.

    This recursive fibonacci function works
    (def! fib (fn* (N) (if (= N 0) 1 (if (= N 1) 1 \
    (+ (fib (- N 1)) (fib (- N 2)))))))

    So the idea that Forth dictionary entries can serve as lisp "objects"
    and that wordlists can serve as hashes has worked so far.

    Kas
    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 -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From NN@21:1/5 to none albert on Mon Jul 10 06:27:03 2023
    On Friday, 7 July 2023 at 13:15:31 UTC+1, none albert wrote:
    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 -


    I did not know Mr Moore was a student of McCarthy.

    If its the case Mr Moore was knowledgeable about lisp its not a big leap to see him
    coming up with a simpler version we now know as forth. But I have never seen
    Mr Moore say that either, so perhaps we are wrong to make this assumption.
    ( can someone can ask at the next svfig meeting ? )

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From ccurl609@gmail.com@21:1/5 to All on Wed Jul 12 06:03:23 2023
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From NN@21:1/5 to ccur...@gmail.com on Thu Jul 13 09:59:17 2023
    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 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

    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 ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From none) (albert@21:1/5 to november.nihal@gmail.com on Thu Jul 13 20:43:26 2023
    In article <c5639efe-14c0-47ca-8631-78f502275a37n@googlegroups.com>,
    NN <november.nihal@gmail.com> wrote:
    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 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

    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 ?

    A simple method is to compile it and than copy the result in line.
    It requires a bit of carnal knowledge.

    10 \ Alias of :, define a word that inlines it code.
    11 : :I CREATE IMMEDIATE ] LATEST HIDDEN !CSP
    12 DOES> STATE @ IF BEGIN $@ DUP '(;) <> WHILE , REPEAT 2DROP
    13 ELSE >R THEN ;

    It is state smart so that it executes in interpret mode.
    It handles unpaired returns stack manipulations,
    but obviously that can only be used in compile mode.
    It copies the compiled code after CREATE into the current definition
    until an EXIT i.e. (;) is encountered.
    If relative branches are used, it happily inserts loops and ifs.
    (;) is an alias for EXIT , such that the code can contain an exit.

    Don't bother with POSTPONE's , that is cumbersome.

    LATEST HIDDEN is to be replaced by code to manipulate the smudge
    bit or some such.

    It is not really that hard.

    Example
    :I add + ;

    : sum3 add add ;

    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 -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)