Re: [stack] language hierarchy

Manfred Von Thun <[email protected]>
Newsgroups gmane.comp.lang.concatenative
Message-ID <C3C52D2F.DF4%[email protected]>
On 16/1/08 6:03 PM, "Manfred Von Thun" <[email protected]> wrote:

[.. stuff about use before definition..]

> The same trick of using forward declarations could also be used if one
> really wants to have definitions to have first the body and then the name
> (presumably no explicit parameters in a concatenative language). Then a
> simply recursive definition would look like this:
> 
> [] def foo (* the forward declaration with dummy body*)
> 
> [.. foo.. foo..] def foo (* the full definition with recursive calls *)

I must have had a senior moment (that is what some of my retired colleagues
call the phenomenon) when I wrote this. To some extent I was thinking of a
compiled
implementation with compile time type checking, but even that does not work
out.

In an interpreted implementation where all the type checking is done
at run time, the following is possible: when a symbol is first encountered,
enter it into the symbol table. Whenever a body of a definition is given,
enter that body in the table for the symbol. Some symbols might never get
a definition because they are not intended to be executed. This happens
for example in lists: [peter paul mary]. But it could also happen
accidentally
when an attempt is made to execute the body of an undefined symbol.
At any rate it is possible to use a symbol (say: bar) in the body of a
definition of another symbol (say: foo). This is how it looks in Joy

DEFINE foo == 42 bar.

At this point bar is not yet defined, so it cannot be executed. Hence foo
cannot be executed although it is defined.

DEFINE bar == 2 *.

Now both foo and bar are defined and can be executed.

If there is self-recursion.as in the following, then there is not problem:

DEFINE baz == ... baz ... .

The first baz enters the symbol into the table, the second finds its
position in the table, and the final period attaches the body to the
position in the table.

Finally, mutual recursion:

DEFINE zot == ... zot ... wow ... .
DEFINE wow == ... wow ... zot ... .

In the definition of zot, the wow is entered and will be found subsequently,
as on the two occasions in the second definition. So this is just like
the earlier case of foo and bar. In the definition of wow, the zot of
course finds its position in the table, and the wow finds a different one,
just as for self-recursion.

All the above definitions could be written in the reverse style, with body
first and head second. Just the last two:

[... zot ... wow ...] def zot
[... wow ... zot ...] def wow

So the idea of entering a symbol into the table as soon as the symbol
is first encountered makes it possible to have self-recursion and even
mutual recursion without any forward or prototype declarations.

HOWEVER: This is fine if type checking is done at run time, but what
about type checking at compile time? In Pascal the forward declarations
and in  C the prototypes give the user not just the names of the
procedures or functions, but also the types of the parameters and the
the type of the result. In a stack language there will only be one
parameter, a stack, and the result will also be a stack. Both stacks
will have to be typed, and a notation is needed for that. My proposal
would be to borrow some ideas from Prolog. For example, the notation

[  N:num X | R ]

would describe a stack of at least two elements, topmost a number N,
second something of any type,followed by a possibly empty
rest-of-stack R. Similarly the notation

[ M:num N:num | R ]

would desribe a stack of at least two elements, two numbers, not
necessarily distinct. Then the definition

DEFINE f == swap pop dup 10 *

defines f to take as input stack one as described by the first description
above, an yield as output one as described by the second description.
Thus the type of f is given by

f  :  [ N:num X | R] -> [M:num N:num | R]

Note that N and R occur on both sides of the arrow, and this indicates
that the input and result stacks are the same in both positions.

A complete definition of f should then combine the typing and the code:

DEFINE f : [N:num X| R] -> [M:num N:num | R] == swap pop dup 10 *

Similar typing could be given for all definitions, and forward/prototypes
would merely give the typing.

Incidentally, the example also illustrates something else: that pattern
matching can describe arbitrarily complex stack shuffling by swap,
pop, dup and friends (and also list shuffling by cons, first, rest and
friends.
But the implications of that are outside this note.

  - Manfred  
> 
> 



[Non-text portions of this message have been removed]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.