Re: [stack] YACL - Yet Another Concatenative Language

sa@dfa.com — 2003-07-02 19:42:22

there's another way to look at this behavior. if you want to avoid
the appearance of naked operators on the stack, you can either quote
them in some way before pushing them, or let them appear and then
re-evaluate the stack by pushing its elements one-at-a-time onto the
empty stack. you keep doing that until all the stack-items are
"inert"; i.e., re-evaluation leaves the stack unchanged.

in cK i provide this as an alternate evaluation behavior ('1 naked').
e.g.

1 naked
[2 3 +] unstack
5

the core of the interpreter is the 'a' function, which takes a stack
x and a single item y to evaluate and returns a new stack: if y is
an operator apply y to x else append y to x:

a:{:[7=4:y;y x;x,,y]}

to get the relentlessly self-pushing behavior:

a:{:[7=4:y;()_f/y x;x,,y]}

i.e. if y is an operator, apply it to the stack, and then keep applying
the current function (_f) to it until you get the same result
twice-in-a-row.
this uses the 'converge' adverb/combinator of k/cK.

since the problem case is in some sense "pathological", or at least rare,
you wind up paying a tiny cost for the superfluous appends.

under this regime, you get some pretty spectacular chain-reactions:

1 naked
-30 trace
[[2 3 + pop] unstack] unstack
[[2 3 + pop] unstack]
[[2 3 + pop] unstack] unstack
[2 3 + pop]
[2 3 + pop] unstack
2
2 3
2 3 +
5
5 pop


btw, since today is my birthday, and my age is mathematically, if not
- alas - biologically reversible, i can announce the k implementation
of brent's brain-twisting (but morally uplifting) language, befreak:

http://www.nsl.com/papers/befreak.htm





phimvt@...
obe.edu.au To: concatenative@yahoogroups.com
cc:
07/01/03 10:42 PM Subject: [stack] YACL - Yet Another Concatenative Language
Please respond to
concatenative







On Sun, 29 Jun 2003, Brent Kerby wrote:

[...]

> Good point. Joy's semantics with these unquoted operators has
always baffled
> me a bit. As I see it, operators like 'first' that pull lists apart fall
> into a different class from more well-behaved combinators like 'swap',
> 'dup', 'cons', 'cat', 'tack', etc.

Example: In a particular family there are children [peter paul mary]
and pets [dup dip pop] and kitchen tables [square round] and for
the next month guests will be expected on the dates [3 8 17 22 29].
In each case, to get the first item of the respective lists you
use the 'first' operator. This will always work, even though 'dup'
is a Joy builtin and 'square' is defined in a library. It will
continue to work even if in the future 'peter' becomes a builtin
or is defined in a library. All pretty regular, I think.

[...]

> So then, here's another possible way of solving your problem, other
than
> using an escape ... When we do "[+] first", then there is something on
the
> stack, call it +' .

This postfix quote may be OK for the program, but what ends up on the
stack should not be this quoted thing. One would want to be able to
cons the top item into another list/quotation, maybe to be executed,
maybe to be written. If the quoted thing ends up on the stack, then
you need another dequote operation to be able to cons it into something
else.

One may very well want a unary quotation operator, say your postfix
quote or a prefix Q. Note that this is a different sense of 'unary',
not the sense in which 'rest', 'not', 'square' are (semantically)
unary. Whatever the exact notation used, "+'" or "Q+" or "Q +" will
be an atom which pushes the (binary) addition operator, or whatever
the argument of the "'" or "Q" is. So in general,
[foo] first == foo' == Q foo
But the "'" or "Q" cannot stand on their own, they need an atom
as an argument to become syntactically correct. In the grammar
there would need to be another production:
factor ::= "Q" factor
This raises the question of what 'Q Q Q foo' should mean.
Perhaps the same as 'Q foo'. The implementation of Q would not
be quite as trivial as it may look, even just for single Q's,
because Q is not just another atom. Is it worth it ?

[...]

> (Perhaps it would be handy for Joy to have syntax
> directly for unquoted operators so they don't have to be constructed
> sneakily using 'first').

You are not persuaded? You don't like sneaky Joy? You want Yacl :

YACL = Yet Another Concatenative Language

Every syntactically correct Joy program is also a syntactically
correct Yacl program. The difference is in the semantics. What
in Joy are called operators and combinators are exactly like
literals in Yacl: when executed they result in a push operation.
So after the execution of
5 dup *
the stack will contain three items: '*' on top, 'dup' second,
and '5' third. (So execution is a bit like reversal, if you think
of the stack as a list). Quotations are left untouched, so
[1 2] [foo bar] concat
result in a stack of three items, 'concat' on top, '[foo bar]'
second, '[1 2]' third.

What is the point, you ask? Well, everything is treated as if it
were quoted, either as '[foo] first' or as "foo'" or as "Q foo"
So there is no need for the unary quotaion operator in Yacl.

But how does Yacl do any computation, like the square or 5 ?
Easy: There is another atom, not a unary operator, called 'E'
for 'execute'. The square of 5 is computed by either
5 dup E * E
or 5 E dup E * E
Semantically the E executes the top single item on the stack in
the same way that Joy would. If that item is an operator or combinator
E will execute it as such. If that item is a literal such as 5,
then E will push it on the stack. So for literals x, x E == x.
One could define such an E in Joy as E == [] cons i, of course,
and the little joy-in-joy uses something like that. But E in Joy
would be rarely used, in Yacl it is essential. One more example:
[1 2 3 4] [dup E * E] map E ==> [1 4 9 16]
In the now very exceptional case where you actually want the E
on top of the stack you would need '[E] first E', unless you
want to introduce a unary quotation operator: "E'" or "Q E".

End-of-Yacl-manual

Thank you all, I really enjoy (!) these discussions.

- Manfred



To unsubscribe from this group, send an email to:
concatenative-unsubscribe@egroups.com



Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/

Tanksley, William D. Jr. — 2003-07-03 15:09:56

From: sa@... [mailto:sa@...]

>there's another way to look at this behavior. if you want to avoid
>the appearance of naked operators on the stack, you can either quote
>them in some way before pushing them, or let them appear and then
>re-evaluate the stack by pushing its elements one-at-a-time onto the
>empty stack. you keep doing that until all the stack-items are
>"inert"; i.e., re-evaluation leaves the stack unchanged.

In my opinion, the real problem here is the confusion in Joy between
delisting and execution, and correspondingly between enlisting and
quotation.

This confusion becomes more difficult when you add array-processing to the
language. While playing with cK I realised why Joy's quotation makes me
uncomfortable, and what I'm going to do about it. No need to change Joy, of
course, but my language will distinguish between quotation and enlistment --
and more importantly, between delistment and execution. My equivalent to the
'i' combinator will take a scalar as an argument, not a list. If you want to
execute a list, you iterate over its elements using the stack as the
"accumulator". If the list happens to be quoted, this is exactly equivalent
to Joy's 'i' combinator.

Quotation will be handled in a similar manner to Lisp; a prefix ' operator
can appear before defined symbols or literals (including literal lists, in
which case everything in the list is quoted). However, lack of quotation
will mean that the words appearing in the [] will be executed, and then the
resulting stack will be enlisted.

The reason I'm doing this is simply that it makes so much more sense in an
array-manipulation language. All the old functionality is still available,
but it now becomes possible to more precisely control how execution happens
in lists.

But I think it also helps when you consider the theory of the language, too.

-Billy

stevan apter — 2003-07-03 15:54:11

i've read this several times, and i'm still having trouble
visualizing the proposal (probably because i spent the previous
hour immersed in the adventures of brad christiansen -- e.g.
http://www.quatloos.com/brad-c/elvis.htm. careful! this
is the email equivalent of those famous inverting prism
spectacles you encountered in psych 101.)

perhaps you can provide a few examples to illustrate the
language? (and send along a bank account # into which i can
wire a donation to the project.)


----- Original Message -----
From: "Tanksley, William D. Jr." <william.d.tanksley.jr@...>
To: <concatenative@yahoogroups.com>
Sent: Thursday, July 03, 2003 11:09 AM
Subject: RE: [stack] YACL - Yet Another Concatenative Language


> From: sa@... [mailto:sa@...]
>
> >there's another way to look at this behavior. if you want to avoid
> >the appearance of naked operators on the stack, you can either quote
> >them in some way before pushing them, or let them appear and then
> >re-evaluate the stack by pushing its elements one-at-a-time onto the
> >empty stack. you keep doing that until all the stack-items are
> >"inert"; i.e., re-evaluation leaves the stack unchanged.
>
> In my opinion, the real problem here is the confusion in Joy between
> delisting and execution, and correspondingly between enlisting and
> quotation.
>
> This confusion becomes more difficult when you add array-processing to the
> language. While playing with cK I realised why Joy's quotation makes me
> uncomfortable, and what I'm going to do about it. No need to change Joy, of
> course, but my language will distinguish between quotation and enlistment --
> and more importantly, between delistment and execution. My equivalent to the
> 'i' combinator will take a scalar as an argument, not a list. If you want to
> execute a list, you iterate over its elements using the stack as the
> "accumulator". If the list happens to be quoted, this is exactly equivalent
> to Joy's 'i' combinator.
>
> Quotation will be handled in a similar manner to Lisp; a prefix ' operator
> can appear before defined symbols or literals (including literal lists, in
> which case everything in the list is quoted). However, lack of quotation
> will mean that the words appearing in the [] will be executed, and then the
> resulting stack will be enlisted.
>
> The reason I'm doing this is simply that it makes so much more sense in an
> array-manipulation language. All the old functionality is still available,
> but it now becomes possible to more precisely control how execution happens
> in lists.
>
> But I think it also helps when you consider the theory of the language, too.
>
> -Billy
>
>
> To unsubscribe from this group, send an email to:
> concatenative-unsubscribe@egroups.com
>
>
>
> Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>

Tanksley, William D. Jr. — 2003-07-03 16:39:49

From: stevan apter [mailto:sa@...]

>i've read this several times, and i'm still having trouble
>visualizing the proposal

No suprise -- although I apologise. I've written that message three times
and had it bounce twice, so I was getting a little incoherent.

At the most primitive level, I purpose to remove Joy's current concept of
"quotations" by redefining all words which currently take a quotation into
words which take a function on the stack. I will, of course, provide syntax
to place a function as a literal (onto the stack, into a list, or anywhere
else a literal can go).

The reasons I want to do this are many -- Joy's quotations have irritated me
on a theoretical level for a long time -- but the one you'll probably find
most understandable is that I want 'i' to be useful when iterating through
lists. Right now 'i' is defined on lists, so cK's iteration isn't usable on
it.

The basic idea has been percolating in my mind for a long time, but it
really came to the forefront when you explained k8 to me. I realised that
Joy just couldn't handle that interpretation of transposition (sorry,
Joy-list people; this is an inside reference from a private email, and you
aren't meant to understand it), but that my earlier language design could
quite easily.

This made me put some more thought into my earlier discomfort with Joy's
quotations, and what I finally came up with was that I was more comfortable
with execution as an atomic operation.

>(and send along a bank account # into which i can
>wire a donation to the project.)

:-)

-Billy

stevan apter — 2003-07-03 17:29:56

----- Original Message -----
From: "Tanksley, William D. Jr." <william.d.tanksley.jr@...>
To: <concatenative@yahoogroups.com>
Sent: Thursday, July 03, 2003 12:39 PM
Subject: RE: [stack] YACL - Yet Another Concatenative Language


> From: stevan apter [mailto:sa@...]
>
> >i've read this several times, and i'm still having trouble
> >visualizing the proposal
>
> No suprise -- although I apologise. I've written that message three times
> and had it bounce twice, so I was getting a little incoherent.
>
> At the most primitive level, I purpose to remove Joy's current concept of
> "quotations" by redefining all words which currently take a quotation into
> words which take a function on the stack. I will, of course, provide syntax
> to place a function as a literal (onto the stack, into a list, or anywhere
> else a literal can go).
>
> The reasons I want to do this are many -- Joy's quotations have irritated me
> on a theoretical level for a long time -- but the one you'll probably find
> most understandable is that I want 'i' to be useful when iterating through
> lists. Right now 'i' is defined on lists, so cK's iteration isn't usable on
> it.

ok, let's see if this matches what you're thinking.

2 3 +
5 still works, right?

2 [3 +]
2 [3 +]

2 [3 +] ) ) is "enclose" - makes a function from a list
2 {3 +} {} is literal function definition
i
5

{3 +} ( ( is "disclose" - makes a list from a function
[3 +]

[+] )
{+}

[3 +] ) )
{{3+}}

[3 +] (
error?

tolerant:

{2}
2

2 )
2

2 (
2

>
> The basic idea has been percolating in my mind for a long time, but it
> really came to the forefront when you explained k8 to me. I realised that
> Joy just couldn't handle that interpretation of transposition (sorry,
> Joy-list people; this is an inside reference from a private email, and you
> aren't meant to understand it), but that my earlier language design could
> quite easily.

i think you're right.

>
> This made me put some more thought into my earlier discomfort with Joy's
> quotations, and what I finally came up with was that I was more comfortable
> with execution as an atomic operation.
>
> >(and send along a bank account # into which i can
> >wire a donation to the project.)
>
> :-)
>
> -Billy
>
>
> To unsubscribe from this group, send an email to:
> concatenative-unsubscribe@egroups.com
>
>
>
> Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>

Tanksley, William D. Jr. — 2003-07-03 18:29:14

From: stevan apter [mailto:sa@...]
>ok, let's see if this matches what you're thinking.
> 2 3 +
> 5 still works, right?

Right.

> 2 [3 +]
> 2 [3 +]

Almost -- I'm using a different syntax to quote, so you could write this as:

2 '[3 +]
or:
2 [3 '+].

> 2 [3 +] ) ) is "enclose" - makes a function from a list
> 2 {3 +} {} is literal function definition
> i
> 5

My initial language won't have "enclose" nor literal function definition,
but it's possible, yes. Either would probably be simple in cK.

> {3 +} ( ( is "disclose" - makes a list from a function
> [3 +]

I definitely won't have disclose.

> [3 +] ) )
> {{3+}}

Double enclose would be a no-op for me, if I implemented it. You can
definitely enlist it and then enclose the result, though.

I think you've got the basic idea, although all your examples are things I
won't be implementing (because I don't want to bother with enclose for now,
and I don't think disclose is worth the effort). Some other examples:

'[2 3 +] unlist
2 3 '+
'[2 3 +] unquote
[5]

-Billy

phimvt@lurac.latrobe.edu.au — 2003-07-04 07:05:59

On Thu, 3 Jul 2003, Tanksley, William D. Jr. wrote:

[..]

> At the most primitive level, I purpose to remove Joy's current concept of
> "quotations" by redefining all words which currently take a quotation into
> words which take a function on the stack.

You can at least get the appearance of this in Joy by suitable
definitions:
DEFINE squareq == [dup *] .
[1 2 3 4] squareq map. ==> [1 4 9 16]

[..]

> The reasons I want to do this are many -- Joy's quotations have irritated me
> on a theoretical level for a long time --

I had noticed your dislike before, and it worried me. But I don't
think I ever replied. Let me explain:

Some languages treat functions as first class objects: functions can
take functions as parameters and functions can return functions.
Many more languages at least allow functions to take functions as
parameters. Since these languages are lambda calculus based, any
function used as a parameter must essentially be a lambda abstraction.
It may of course be that the actual parameter is a word that has
been to be a lambda abstraction, with perhaps syntactic sugar:
DEFINITION foo(x y) = ..x..y.. sugared
DEFINITION foo = Lambda x y : ..x..y.. raw
The two are entirely equivalent.

Now suppose we have a function that takes a function as one parameter,
say the function bar. It may now use an explicit lambda abstraction
or what has been defined to be a lambda abstraction:
bar(Lambda x y : ..x..y.., other-parameters)
bar(foo, other parameters)
The two are entirely equivalent. The second looks neater, but it
requires the definition of foo somewhere. If the function foo
is only ever used once, as a parameter to the function bar, one
might well prefer the explicit lambda and never define foo at all.

If a language is not based on the lambda calculus but still
will provide functions as parameters, then something else will
have to take the place of lambda abstractions. Whatever that
something is, it will have to be something that could be the
body of a named function. It will have to be like ..x..y..
above, but do without the x and y. So let us write it as
..?..?.. . The details will depend on the details of the language.
Semantically it might be a stack based language or one based
on some other structure that serves a similar purpose.
Syntactically it may be that ..?..?.. is actually a term
f(g?,h?) with no need for an indicator where it starts and ends.

But in a concatenative language there are no such terms,
and some begin/end indicators are needed, Joy uses [ and ].
So it seems to me that if Joy wants functions as parameters
(indeed, functions as first class values), then it needs
quotations. It so happens that they also allow other useful
combinators such as dip, without the need for an explicit
dip-stack (similar to the use of the return stack in Forth).

Does one need functions as parameters to other functions?
The functional programming community thinks that at least
map, fold and filter are very useful for manipulating lists.
Joy agrees. One does not need these higher order functions,
of course, one can always write a recursive list precessing
definition instead, using the standard patterns embodied
in map, fold and filter. But that can become cumbersome
if the function has to be defined even if it is used only once.
Joy can even have combinators like linrec and binrec which
have nothing in particular to do with lists. I think the
same would be true for some other possible languages that
are not based on the lambda calculus.

Before embarking on this note, I should have asked you, Billy,
whether your dislike is for the syntax of Joy quotations
or for the semantics, or perhaps their use in higher order
functions. I would be happy to elaborate.

I am almost at the point where I should raise my question
about adverbs in APL, J, K and cK, but right now I am too tired.

Have a nice weekend.

- Manfred

Martin Young — 2003-07-04 11:28:35

Curiously, or maybe not, Monkey already does something superficially
quite similar to this but for different reasons: I wanted to add a
simple type system to Monkey, and I wanted to be able to give a compiler
static hints about which lists to compile.

Each thing (for want of a better word) in a program has a major type and
a minor type. Major types are integers, floats, booleans, words, atoms,
lists, etc. Lists, for example, have two minor types: data and program.

Most list manipulation words like cons, length, etc are defined for all
things of major type list whereas words which take programs as
parameters are defined only for things of major type list and minor type
program. List/program literals are denoted with curly braces whereas
list/data literals use normal square brackets.

Instead of "enclose" I have a word "programise" which turns a list/data
into a list/program. Similarly to Billy's description, I don't have a
"disclose" equivalent and "programise" (or "enclose") is idempotent.

Thus trying to execute "2 [ 2 + ] i" would cause a type error. It would
need to be either "2 [ 2 + ] programise i" or (preferably) "2 { 2 + }
i".

Where Monkey differs again is in a distinction between program words and
atoms. In Monkey, Manfred's example [peter paul mary] would cause an
undefined word error on startup - every literal word must be either a
primitive word or be defined in a module. One would use atoms instead
i.e. ['peter 'paul 'mary]. Atoms and words are separate major types -
there is no general way to transform one into the other.

I'm thinking that Billy's scalar execute word (let's call it si) is
actually the atom->word transformer which I've disallowed. That is, all
words are, by default, not executed (in Monkey, they're of type atom not
type word) but may be executed explicitly through a scalar execution
word (in Monkey the datum of type atom would be transformed into a datum
of type word then put in a unit list, programised and dequoted i.e. si
== {{ atomtoword unit programise i }}.

Now, I /think/ the distinction between words and atoms is syntactic
sugar only. One could simply use words instead and provide empty
definitions for those ex-atoms which aren't useful words in their own
right. That is, my description of how si might be defined in Monkey is
equally valid for Joy.

If true then it's quite simple to synthesise Billy's described semantics
in Joy. That is, they don't actually add anything new, they're just
another (albeit interesting) recasting of Joy in terms of different
primitives.

Am I missing something? I don't, to be honest, see the problem
(practically or theoretically) the recasting is intended to solve.

On Thu, 2003-07-03 at 19:29, Tanksley, William D. Jr. wrote:
> From: stevan apter [mailto:sa@...]
> >ok, let's see if this matches what you're thinking.
[snip]
> I think you've got the basic idea, although all your examples are things I
> won't be implementing (because I don't want to bother with enclose for now,
> and I don't think disclose is worth the effort). Some other examples:
[snip]

--
Martin Young, at home.

Nick Forde — 2003-07-04 12:55:52

Martin Young writes:
[lots of interesting Monkey details...]
> Now, I /think/ the distinction between words and atoms is syntactic
> sugar only. One could simply use words instead and provide empty
> definitions for those ex-atoms which aren't useful words in their own
> right. That is, my description of how si might be defined in Monkey is
> equally valid for Joy.
>
> If true then it's quite simple to synthesise Billy's described semantics
> in Joy. That is, they don't actually add anything new, they're just
> another (albeit interesting) recasting of Joy in terms of different
> primitives.
>
> Am I missing something? I don't, to be honest, see the problem
> (practically or theoretically) the recasting is intended to solve.

After reading Billy's mail last night I reached the same conclusion
but also thought I must be missing something. Even after sleeping on
it I can see that explicitly distinguishing words and quotations may
provide a compiler with some useful hints but I haven't yet found a
compelling example to illustrate why one approach may be preferable to
the other.

John's example below did raise one question in my mind:

"p" "op" concat intern [] cons i.

In Joy is there any reason why 'i' may only work on quotations? Why
not allow:

1 2 "p" "op" concat intern i.
1

or:

1 2 [pop] first i.
1

or even:

1 2 i.
2

i.e. make the i combinator polymorphic so that it the following would
be equivalent:

1 2 [+ 2 *] i.
6

1 2 [+ 2 *] [null] [pop] [uncons [i] dip] tailrec.
6

Regards,

Nick.

stevan apter — 2003-07-04 13:59:42

----- Original Message -----
From: "Nick Forde" <nickf@...>
To: <concatenative@yahoogroups.com>
Sent: Friday, July 04, 2003 8:55 AM
Subject: RE: [stack] YACL - Yet Another Concatenative Language


> Martin Young writes:
> [lots of interesting Monkey details...]
> > Now, I /think/ the distinction between words and atoms is syntactic
> > sugar only. One could simply use words instead and provide empty
> > definitions for those ex-atoms which aren't useful words in their own
> > right. That is, my description of how si might be defined in Monkey is
> > equally valid for Joy.
> >
> > If true then it's quite simple to synthesise Billy's described semantics
> > in Joy. That is, they don't actually add anything new, they're just
> > another (albeit interesting) recasting of Joy in terms of different
> > primitives.
> >
> > Am I missing something? I don't, to be honest, see the problem
> > (practically or theoretically) the recasting is intended to solve.
>
> After reading Billy's mail last night I reached the same conclusion
> but also thought I must be missing something. Even after sleeping on
> it I can see that explicitly distinguishing words and quotations may
> provide a compiler with some useful hints but I haven't yet found a
> compelling example to illustrate why one approach may be preferable to
> the other.

commute == [first unit [swap] match]
[1 swap drop ]
[[swap] swap concat ] ifte

[+] commute
[swap +]
commute
[+]

if programs were atoms, you would need some way of breaking out the
underlying list, prepending or removing the 'swap', then making
the resulting list a program. martin's 'programise' will do that,
and so would enclose/disclose. but i'm with you on the general question:
what does this extra machinery buy you? or perhaps: what difficulties
in the present approach does it extricate you from?

>
> John's example below did raise one question in my mind:
>
> "p" "op" concat intern [] cons i.
>
> In Joy is there any reason why 'i' may only work on quotations? Why
> not allow:
>
> 1 2 "p" "op" concat intern i.
> 1
>
> or:
>
> 1 2 [pop] first i.
> 1
>
> or even:
>
> 1 2 i.
> 2
>
> i.e. make the i combinator polymorphic so that it the following would
> be equivalent:
>
> 1 2 [+ 2 *] i.
> 6
>
> 1 2 [+ 2 *] [null] [pop] [uncons [i] dip] tailrec.
> 6

right. that's the way things work in cK.

2 3 [+] first i
5

for any atom, disquotation of it is that atom:

3 5 i
3 5

(this contradicts your example above: why should 1 2 i -> 1?)


>
> Regards,
>
> Nick.
>
>
>
> To unsubscribe from this group, send an email to:
> concatenative-unsubscribe@egroups.com
>
>
>
> Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>

stevan apter — 2003-07-04 14:03:21

----- Original Message -----
From: "Martin Young" <martin@...>
To: <concatenative@yahoogroups.com>
Sent: Friday, July 04, 2003 7:28 AM
Subject: RE: [stack] YACL - Yet Another Concatenative Language


>
> Now, I /think/ the distinction between words and atoms is syntactic
> sugar only. One could simply use words instead and provide empty
> definitions for those ex-atoms which aren't useful words in their own
> right.

i think you're right.

in implementing cK i struggled with this for a while and eventually
decided to defer evaluation of words to run-time. so e.g.

[peter paul mary] `folksingers def
`folksingers
pop folksingers
N N N

def takes an object and a symbol, returns the symbol and has the
side-effect of assigning the object to the symbol. in this case,
none of the words in folksingers is defined, so its value is a
list three nulls. but then if you say

12 `peter def pop
folksingers
12 N N

exit to k and look at folksingers:

\
folksingers
({o[x;get x;y]}[`peter];{o[x;get x;y]}[`paul];{o[x;get x;y]}[`mary])

which is a list of three functions, each of which gets the value of
the associated symbol.

this is useful in defining mutually recursive functions:

[ ... f ... ] `g def
[ ... g ... ] `f def

Nick Forde — 2003-07-04 14:31:25

stevan apter writes:
> > i.e. make the i combinator polymorphic so that it the following would
> > be equivalent:
> >
> > 1 2 [+ 2 *] i.
> > 6
> >
> > 1 2 [+ 2 *] [null] [pop] [uncons [i] dip] tailrec.
> > 6
>
> right. that's the way things work in cK.
>
> 2 3 [+] first i
> 5
>
> for any atom, disquotation of it is that atom:
>
> 3 5 i
> 3 5
>
> (this contradicts your example above: why should 1 2 i -> 1?)

Sorry, my examples only included the top-of-stack in results. My
intention was also that for atoms, dequotation would be that atom.

Here's an example definition of this polymorphic i combinator which
works in the current Joy interpreter:

DEFINE new_i ==
[
[ [list] i ]
[ [string] intern [] cons i ]
[ [user] [] cons i ]
[ [set ] ]
[ [char] ]
[ [logical] ]
[ [file] ]
[ [integer] ]
[ [] cons i ]
] cond.

(Nb. There really should be a 'prim' test. If there had been I
would have used the default condition for atoms).

Some examples:

[1 2 + 2 *] new_i.
6
1 2 "+" new_i.
3
1 2 "+" [new_i] first new_i.
3
{5} new_i.
{5}
'a new_i.
'a
true new_i.
true
stdin new_i.
file:stdin
1.01 new_i.
1.01
[cons] first 'a "b" rolldown new_i.
"ab"

And the ones from my earlier mail:

1 2 [+ 2 *] new_i.
6
1 2 [+ 2 *] [null] [pop] [uncons [new_i] dip] tailrec.
6

I treated strings differently from other atoms to allow creation of
mini interpreters. File streams could also be read and executed line
by line.

Regards,

Nick.

stevan apter — 2003-07-04 15:11:30

----- Original Message -----
From: "Nick Forde" <nickf@...>
To: <concatenative@yahoogroups.com>
Sent: Friday, July 04, 2003 10:31 AM
Subject: Re: [stack] YACL - Yet Another Concatenative Language


[:]
>
> Here's an example definition of this polymorphic i combinator which
> works in the current Joy interpreter:
>
> DEFINE new_i ==
> [
> [ [list] i ]
> [ [string] intern [] cons i ]
> [ [user] [] cons i ]
> [ [set ] ]
> [ [char] ]
> [ [logical] ]
> [ [file] ]
> [ [integer] ]
> [ [] cons i ]
> ] cond.

:

> 1 2 "+" new_i.
> 3
:

> I treated strings differently from other atoms to allow creation of
> mini interpreters. File streams could also be read and executed line
> by line.

should i expect that '"2 3 +" new_i' falls over? i.e. that intern
is not defined for such cases?

APL has always had an 'execute', which takes a string and invokes
the interpreter, and i have followed suit in cK:

"2 3 +" ck
5
"[2 3 +]" ck
[2 3 +]

"ck" because i want to also have an exit to the k interpreter:

"!3" k
[0 1 2]


>
> Regards,
>
> Nick.
>
>
>
> To unsubscribe from this group, send an email to:
> concatenative-unsubscribe@egroups.com
>
>
>
> Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>

Nick Forde — 2003-07-04 15:34:21

stevan apter writes:
>
> > 1 2 "+" new_i.
> > 3
> :
>
> > I treated strings differently from other atoms to allow creation of
> > mini interpreters. File streams could also be read and executed line
> > by line.
>
> should i expect that '"2 3 +" new_i' falls over? i.e. that intern
> is not defined for such cases?

Yes, new_i was meant for illustration only. I started writing a simple
tokeniser but then realised that to be useful a full Joy parser would
be required to distinguish atoms from words. Although this would be
pretty easy to implement I decided that if this was a desirable
feature then it should use the C Joy analyser and work with strings or
file streams.

> APL has always had an 'execute', which takes a string and invokes
> the interpreter, and i have followed suit in cK:
>
> "2 3 +" ck
> 5
> "[2 3 +]" ck
> [2 3 +]

I think this would be useful in Joy. A more flexible alternative may
be to provide a 'tokenize' primitive that converts a string into a
quotation. This wouldn't work so well with file streams though.

Nick.

John Cowan — 2003-07-04 20:11:19

phimvt@... scripsit:

> Before embarking on this note, I should have asked you, Billy,
> whether your dislike is for the syntax of Joy quotations
> or for the semantics, or perhaps their use in higher order
> functions. I would be happy to elaborate.

I think that would he doesn't like is the formal identity of lists and
quotations, which prevents the compiling of quotations.

In older Lisps, functions were lists, but in newer Lisps (especialy
Scheme), functions are distinct objects created from lists.
Indeed, one could create a dialect of Scheme in which lists/pairs/conses
did not exist, and it would still be Scheme, provided a different
mechanism was created for the representation of functions with
arbitrarily many arguments (R5RS Scheme currently provides the arguments
in the form of a freshly created list).

--
Schlingt dreifach einen Kreis vom dies! John Cowan <jcowan@...>
Schliesst euer Aug vor heiliger Schau, http://www.reutershealth.com
Denn er genoss vom Honig-Tau, http://www.ccil.org/~cowan
Und trank die Milch vom Paradies. -- Coleridge (tr. Politzer)

stevan apter — 2003-07-04 21:28:03

i think i have an argument for a distinct category of function
objects, but it's regrettably convoluted, and i don't know if
anyone will find it convincing.

in k, the shape of an array is defined this way:

the shape of an atom is the empty list.

the shape of a list x is the size of x to which is append the
common initial sublist of the shapes of its elements.

so shape is always a list of integers (possibly empty).

the idea is that you want to penetrate a list as far as
possible, up to the point where you can no longer summarize
the sizes of the lists at that level in a single integer.

examples:

10 shape
[]
[1 2 3] shape
[3]
[[1 2 3][4 5 6]] shape
[2 3]
[[1 2 3][4 5]] shape
[2]

functions are atoms, so they have empty shape. the size of
the shape is called 'rank'. atoms are rank 0, vectors are
rank 1, matrices are rank 2, &c. notice that [[1 2 3][4 5]]
is rank 1, even though its elements are lists.

the rank of an object is related to how it can be indexed.
a vector can be indexed v[i], a matrix m[i;j], and so forth.
atoms can't be indexed. the shape of the result of an index
can be calculated by replacing each element in the shape
with the shape of the corresponding index. for example, if
m has shape [3 4] then the shape of m[1 2;0 2 1] is [2 3],
and that of m[1;0 1] is [2] (since 1 is an atom, we replace
the corresponding element of the shape -- 3 -- with [].)

there is a related concept for functions -- valence. the
valence of a function is the number of arguments it takes.
e.g. the valence of + is 2, that of {x+y-z} 3, and so forth.
since functions are atoms, and atoms can't be indexed, we
re-use the brackets to mean function application: +[2;3],
{x+y-z}[4;5;6], &c.

now we can define the shape of a function of valence k to be
[-1 .. -k]. so the shape of + is [-1 -2], that of {x+y-z}
[-1 -2 -3] &c.

so e.g. the shape of p = [+ -] is 2 -1 -2.

now consider the transpose operation, which flips the first
two axes of an array of rank > 1. if [a b ..] is the shape
of x, then the shape of transposed x is [b a ..]. so the
shape of [+ -] transposed is [-1 2 -2]. what is that thing?
if we believe what the shape is telling us, then it's a
function of two arguments which returns something of shape
[2 ..]. in fact, it's a function which returns a list whose
first element is x+y and whose second is x-y. the transpose
of a list of functions (of the same shape) is a function.

not only primitives, but also constructed programs have
valence, so they too should have shape in this extended sense.
but if programs are lists, then we can't extend shape or transpose
or any other structural operation in this way. the reason we
can't is that [+ *] has shape [2 -1 -2] (it's a list of two
function atoms!), whereas we want it to have shape [-1 -2 -3].

that is, we want to be able to form the list [+ -] with shape
[2 -1 -2], but we also want to be able to construct the program
of shape [-1 -2 -3] which in joy we also write [+ -].



----- Original Message -----
From: "John Cowan" <cowan@...>
To: <concatenative@yahoogroups.com>
Sent: Friday, July 04, 2003 4:11 PM
Subject: Re: [stack] YACL - Yet Another Concatenative Language


> phimvt@... scripsit:
>
> > Before embarking on this note, I should have asked you, Billy,
> > whether your dislike is for the syntax of Joy quotations
> > or for the semantics, or perhaps their use in higher order
> > functions. I would be happy to elaborate.
>
> I think that would he doesn't like is the formal identity of lists and
> quotations, which prevents the compiling of quotations.
>
> In older Lisps, functions were lists, but in newer Lisps (especialy
> Scheme), functions are distinct objects created from lists.
> Indeed, one could create a dialect of Scheme in which lists/pairs/conses
> did not exist, and it would still be Scheme, provided a different
> mechanism was created for the representation of functions with
> arbitrarily many arguments (R5RS Scheme currently provides the arguments
> in the form of a freshly created list).
>
> --
> Schlingt dreifach einen Kreis vom dies! John Cowan <jcowan@...>
> Schliesst euer Aug vor heiliger Schau, http://www.reutershealth.com
> Denn er genoss vom Honig-Tau, http://www.ccil.org/~cowan
> Und trank die Milch vom Paradies. -- Coleridge (tr. Politzer)
>
>
> To unsubscribe from this group, send an email to:
> concatenative-unsubscribe@egroups.com
>
>
>
> Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
>
>

Tanksley, William D. Jr. — 2003-07-07 14:59:26

From: stevan apter [mailto:sa@...]
>that is, we want to be able to form the list [+ -] with shape
>[2 -1 -2], but we also want to be able to construct the program
>of shape [-1 -2 -3] which in joy we also write [+ -].

Wow. You've stated my problem formally and precisely: I want to be able to
distinguish between programs and lists of programs.

The idea of giving functions negative rank is new to me.

-Billy

Tanksley, William D. Jr. — 2003-07-07 18:39:42

From: phimvt@... [mailto:phimvt@...]
>On Thu, 3 Jul 2003, Tanksley, William D. Jr. wrote:

>>At the most primitive level, I purpose to remove Joy's
>>current concept of "quotations" by redefining all words
>>which currently take a quotation into words which take
>>a function on the stack.

>You can at least get the appearance of this in Joy by suitable
>definitions:

> DEFINE squareq == [dup *] .
> [1 2 3 4] squareq map. ==> [1 4 9 16]

You can get the reality of this in Joy by suitable definitions:

DEFINE execute == enlist i.
2 3 [+] first execute. ==> 5

Of course, I don't have the ability to use function references directly, but
as you can see I can just use [?] first as a substitute.

I could define all of the combinators for my system using Joy's combinators,
and if I were attempting to produce a successor to Joy, I would do this as a
proof of concept.

>>The reasons I want to do this are many -- Joy's quotations
>>have irritated me on a theoretical level for a long time --

>I had noticed your dislike before, and it worried me. But I don't
>think I ever replied. Let me explain:

I've never before been able to articulate my dislike properly, and naturally
nobody's understood it. Apter has done me the favor of expressing
_precisely_ my problem with quotations, although in very technical terms; a
less formal way of stating my problem is that I want to be able to treat
lists differently from functions.

>If the function foo is only ever used once, as a parameter to
>the function bar, one might well prefer the explicit lambda
>and never define foo at all.

One _might_ prefer that -- or one might not. Or the language might not offer
the option. Python, although it offers lambdas, deliberately cripples them
(even in the current version of the language, which has lexical scoping at
last); programmers traditionally define a function named "_" and pass that,
if they can't think of a more meaningful name.

Let me invent a couple of terms. A "function literal" is how you pass any
function as a parameter (or return value). Lisp uses #' to express function
literals. An "expression literal" allows you to treat an expression as a
literal, in order to pass it or manipulate it.

To support first-class functions you have to support function literals. You
DON'T have to support expression literals.

Joy has expression literals (quotations), but it uses them *instead* of
function literals. Function literals don't appear in Joy's syntax or
definition, even though Joy programs can accept and return functions ([+]
first returns a function).

>So it seems to me that if Joy wants functions as parameters
>(indeed, functions as first class values), then it needs
>quotations. It so happens that they also allow other useful
>combinators such as dip, without the need for an explicit
>dip-stack (similar to the use of the return stack in Forth).

Anything that quotations can do, functions can do as well.

Almost anything.

Quotations, as I've mentioned before, are expression literals; as such, you
can do expression manipulation on them. You can't neccessarily do that for
functions.

Quotations do serve a useful purpose. My problem isn't really their
presence, although my language won't initially have them; my problem is that
people are confusing them with functions, and as a result having all kinds
of theoretical confusion involving equality and such. This theoretical
confusion leads to a slowdown of progress in understanding this new topic,
concatenative languages; it also limits the functionality we could be
adding, for example combinators that handle arbitrary lists of functions and
items (which doesn't work if you can't tell the difference between a list
and a function).

>I am almost at the point where I should raise my question
>about adverbs in APL, J, K and cK, but right now I am too tired.

cK demonstrates that K's adverbs are most similar to combinators.

J is a little more complex, but the same essentials apply.

> - Manfred

-Billy

sa@dfa.com — 2003-07-07 18:41:18

From: stevan apter [mailto:sa@...]
>that is, we want to be able to form the list [+ -] with shape
>[2 -1 -2], but we also want to be able to construct the program
>of shape [-1 -2 -3] which in joy we also write [+ -].

Wow. You've stated my problem formally and precisely: I want to be able to
distinguish between programs and lists of programs.

+ is a function atom, [+ -] is a list of functions,
[+ -] transpose is a function-list (or "function-
array" - btw [-] tranpose commutes -).

The idea of giving functions negative rank is new to me.

i think it works, but n.b. the valence of {2 3 +}
(or however you choose to write it) is 0, so the
shape is []. that throws a wrench into what i
was thinking at first: x is a function if x shape
first 0 <.

-Billy


To unsubscribe from this group, send an email to:
concatenative-unsubscribe@egroups.com



Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/

Tanksley, William D. Jr. — 2003-07-07 18:49:50

From: sa@... [mailto:sa@...]
>[Billy said:]
>>The idea of giving functions negative rank is new to me.
>i think it works, but n.b. the valence of {2 3 +}
>(or however you choose to write it) is 0, so the
>shape is []. that throws a wrench into what i
>was thinking at first: x is a function if x shape
>first 0 <.

Hm. Yes, I see other problems too -- for example, what's the shape of {3 2}?
How about {3 + 3}?

Shape doesn't seem unreasonable to me; in fact, it's the basis for my plans
for my language. But functions don't have a shape the same way literal
arrays have a shape; instead, they have a stack effect, and each item in the
effect has a shape. Literals also have a shape.

-Billy

sa@dfa.com — 2003-07-07 19:38:43

[billy said:]

Hm. Yes, I see other problems too -- for example, what's the shape of {3
2}?
How about {3 + 3}?

and then there's [[*] times] and [[0 <] [*] [+ *] ifte] and ...

my argument was that if you want function arrays, then they can't
be lists. it may be that function arrays aren't important, or
useful, or that they introduce too many complexities. i just
don't know.

Tanksley, William D. Jr. — 2003-07-07 21:01:23

From: Martin Young [mailto:martin@...]

>Where Monkey differs again is in a distinction between program
>words and
>atoms. In Monkey, Manfred's example [peter paul mary] would cause an
>undefined word error on startup - every literal word must be either a
>primitive word or be defined in a module. One would use atoms instead
>i.e. ['peter 'paul 'mary]. Atoms and words are separate major types -
>there is no general way to transform one into the other.

I would have a general way to trasfer between the two. Oh, and I wouldn't
call them "atoms"; by my terms they're "symbols". Anyhow, to convert from a
symbol to a function one uses 'lookup', and to convert from a function to a
symbol one uses 'name'.

>I'm thinking that Billy's scalar execute word (let's call it si) is
>actually the atom->word transformer which I've disallowed.

No, not at all. Scalar execute simply executes the function on TOS. In your
terms, it takes a word as input.

>That is, all words are, by default, not executed (in Monkey, they're of
>type atom not type word)

No. As with Joy, words are executed (or compiled) by default. The way to
place a function on the stack is to quote its name. One possible syntax is a
preceding apostrophe, as with Lisp and Forth.

>Now, I /think/ the distinction between words and atoms is syntactic
>sugar only.

No -- symbols are used in many modern languages. It's very useful to be able
to express arbitrary symbols.

Assuming, of course, that by "words" you mean "functions" and by "atoms" you
mean "symbols".

>Am I missing something? I don't, to be honest, see the problem
>(practically or theoretically) the recasting is intended to solve.

You've already implemented the major difference: Monkey can tell the
difference between a function and a list of data. The next step is to take
advantage of that: I will do so by implementing combinators which traverse
lists executing functions wherever they appear. This is something that's not
possible in Joy as it stands.

-Billy (for greater justice)

Tanksley, William D. Jr. — 2003-07-07 21:07:59

From: stevan apter [mailto:sa@...]
> commute == [first unit [swap] match]
> [1 swap drop ]
> [[swap] swap concat ] ifte
> [+] commute
> [swap +]
> commute
> [+]

>if programs were atoms, you would need some way of breaking out the
>underlying list, prepending or removing the 'swap', then making
>the resulting list a program. martin's 'programise' will do that,
>and so would enclose/disclose.

This is something Joy already can do. My Forth/Joy won't be able to do it at
all: it won't have any way to decompile or disclose to convert a function
into a list. I will probably eventually write a word which will convert a
list into a function, but I won't initially.

Why not? Simply because I don't need constructed functions right now.
They're a specialised need that I don't have. Once I build a global
optimiser, of course, I _will_ need them; but it's not certain to me that
I'll need a global optimiser. Simple native-code generation with basic
peephole optmization and register allocation tends to get very close to GCC
performance for Forth, and I don't see why my language should be any
different.

-Billy

phimvt@lurac.latrobe.edu.au — 2003-07-08 06:18:17

On Fri, 4 Jul 2003, John Cowan wrote:

> phimvt@... scripsit:
>
> > Before embarking on this note, I should have asked you, Billy,
> > whether your dislike is for the syntax of Joy quotations
> > or for the semantics, or perhaps their use in higher order
> > functions. I would be happy to elaborate.
>
> I think that would he doesn't like is the formal identity of lists and
> quotations, which prevents the compiling of quotations.
????????

I don't see that at all. I have spent very little time thinking
about how a compiler for Joy would work, but if it can compile
the body of a definition (which is a term), then it can compile
a quotation (which is also a term), except that it might have to
invent an internal name for that compiled form. Assuming that the
Joy compiler produces C code, then e.g.
[..if-part..] [..then-part..] [..else-part..] ifte
becomes three functions, say f42(), f43(), f44(), and for the
ifte the code
f42();
if (TOS > 1) f(43);
else f44();
The C optimiser can then decide whether the calls to f42(), f43()
and f44() should be inlined. Alternatively the Joy compiler can
do the inlining.

In most Joy programs the quotation parameters immediately precede
the combinators, and the above method should work. In general it
would not be necessary to _also_ retain the quotation in source form.
This is so because all inbuilt combinators and also all library
combinators are _extensional_, in this sense:
for all programs P and Q and for all combinators C,
IF P == Q THEN [P] C == [Q] C

Certainly it is possible to write _intensional_ combinators
for which this is not true, e.g. an intensional i combinator i-i :
DEFINE i-i == dup put i.
Or an intensional map:
DEFINE i-map == dup [map] dip swons.
[1 2 3] [2 *] map ==> [2 4 6]
[1 2 3] [dup +] map ==> [2 4 6]
[1 2 3] [2 *] i-map ==> [[2 *] 2 4 6]
[1 2 3] [dup +] i-map ==> [[dup +] 2 4 6]
I have never seen the need to define intensional combinators,
but maybe one day it will happen. In that case a compiler
will have to produce _both_ the quoted program and the
compiled form of the quotation. But in most cases the compiler
should be able to work out what is needed. Moreover, in the
simplest implementation the compiler could always do both: retain
the source text and produce the compiled form of a quotation.
It is interesting to note that good compilers already do
this to some extent with runtime error checking: depending
on the debug switches, at least the line number or also
the name of the offending operator or even the whole line
is retained to become available for error reporting.
So, if a first version of a Joy compiler did that for every
quotation, it would not be an enormous disaster.

These are my somewhat ill-formed thoughts. Am I missing something?

I will be busy preparing for my courses that are starting soon,
so I will have little time to contribute to the mailing group.
In the meantime my best wishes to the (four ?) people who are
implementing various cousins of Joy.

- Manfred

phimvt@lurac.latrobe.edu.au — 2003-07-08 06:42:45

On Fri, 4 Jul 2003, Nick Forde wrote:

[..]

> Here's an example definition of this polymorphic i combinator which
> works in the current Joy interpreter:
>
> DEFINE new_i ==
> [
> [ [list] i ]
> [ [string] intern [] cons i ]
> [ [user] [] cons i ]
> [ [set ] ]
> [ [char] ]
or: [ [char] "" cons intern [] cons i ]
( to allow for 'i and 'x and 'y to be consistently polymorphic
> [ [logical] ]
> [ [file] ]
> [ [integer] ]
or: [ [integer] chr "" cons intern [] cons i ]
( to allow for 105 and 120 and 121 ('i, 'x, 'y) to be consistent
> [ [] cons i ]
> ] cond.
>
> (Nb. There really should be a 'prim' test. If there had been I
> would have used the default condition for atoms).
(NB. Yes, maybe a prim test, I agree.)

But then the same should be done for all combinators C. Moreover,
it should be done for all operators O too. In that case what little
typechecking there is in Joy would completely go out of the window,
and it would make programming more error prone.

In the rare case where one really wants the latitude which your
new-i and all other new-C and new-O offer, one is probably equally
well served with a 'quotify' operator - defined pretty much like
your new-i but without the terminal i at the end of each case.

- Manfred

John Cowan — 2003-07-08 11:16:53

phimvt@... scripsit:

> [..if-part..] [..then-part..] [..else-part..] ifte
> becomes three functions, say f42(), f43(), f44(), and for the
> ifte the code
> f42();
> if (TOS > 1) f(43);
> else f44();
> The C optimiser can then decide whether the calls to f42(), f43()
> and f44() should be inlined. Alternatively the Joy compiler can
> do the inlining.

Sure. There's no problem with handling lots of individual cases like
this. It's the general case that's hard:

32 [] cons 45 swons 56 swons i

where you have to do an arbitrary amount of analysis, perhaps involving
actual (not abstract) interpretation, to even figure out what the
program is. In Scheme, by contrast, the difference between a function
and a mere list is always lexically visible: the body of a function
cannot (short of using "eval") be concocted at run time in this fashion.

It is in this sense I say that a Joy program *is* a list, as was the
case in early Lisps, whereas in modern Lisps, functions are *made from*
lists. At run-time, the two objects are quite distinguishable.

--
John Cowan jcowan@... www.ccil.org/~cowan www.reutershealth.com
"If I have seen farther than others, it is because I was standing on
the shoulders of giants."
--Isaac Newton