[stack] XY: final draft
stevan apter — 2004-09-22 22:55:23
i've posted the "final" draft on my website:
www.nsl.com/k/xy/xy.htm
i've added an "operations" section which describes how to
actually use the damned thing!
phimvt@lurac.latrobe.edu.au — 2004-09-23 07:09:21
Thanks Stevan. I've saved it as .htm and as .txt
We'll have to decide which format is best for the
joint collection.
Slava - shall I now save your Factor version?
I did not see any comments coming.
Thanks to both.
- Manfred
On Wed, 22 Sep 2004, stevan apter wrote:
>
> i've posted the "final" draft on my website:
>
> www.nsl.com/k/xy/xy.htm
>
> i've added an "operations" section which describes how to
> actually use the damned thing!
sa@dfa.com — 2004-09-23 16:06:55
thank you manfred.
if you don't mind, can you grab it once more? i added a paragraph on
scoping, and documentation for the following new feature.
in joy, explicit recursion requires that the recurring program have a
name. otherwise, you're forced to find a solution using one of the
recursive combinators, to which you can pass the anonymous program
as an argument.
in XY, within a pattern, the special names _x and _y refer to the
stack (minus the elements you've implicitly popped off by specifying
a template) and the queue. e.g. in
{ [a b] _x _y }
_x refers to the stack after you've popped the first two elements
and _y refers to everything in the queue following the pattern.
i've added _z, which refers to the pattern itself. for example,
defining the 'step' combinator as an explicit recursion is:
; step {{ [a p] a [a uncons p dip p step] [] if }} ;
or, using _z:
; step {{ [a p] a [a uncons p dip p _z] [] if }} ;
what is substituted for _z is the pattern itself, and not the
name 'step':
{{ [a p] a [a uncons p dip p _z] [] if }}
here's another example.
suppose you want to define a pattern P which, when executed,
returns the number of elements (#:) in P:
; P {{ [] "P" .g #: }} ;
P
6
i.e.
"P" .g
[{{ [] "P" .g #: }}]
#:
6
This approach requires that P have a name. alternatively,
{{ [_z] #: }}
5
which doesn't.
phimvt@... wrote on 09/23/2004 03:09:21 AM:
>
> Thanks Stevan. I've saved it as .htm and as .txt
> We'll have to decide which format is best for the
> joint collection.
>
> Slava - shall I now save your Factor version?
> I did not see any comments coming.
>
> Thanks to both.
>
> - Manfred
>
> On Wed, 22 Sep 2004, stevan apter wrote:
>
> >
> > i've posted the "final" draft on my website:
> >
> > www.nsl.com/k/xy/xy.htm
> >
> > i've added an "operations" section which describes how to
> > actually use the damned thing!
>
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
William Tanksley, Jr — 2004-09-23 19:15:25
On Wed, 22 Sep 2004 18:55:23 -0400, stevan apter <
sa@...> wrote:
> i've posted the "final" draft on my website:
> www.nsl.com/k/xy/xy.htm
I think you've really got something there, stevan. Your notation and
explanations make sense, and have clarified some of the things I was
having a hard time explaining for Forth.
Now that you've mastered continuations, are you ready to take on
partial continuations? A normal continuation allows you to use "the
rest of the current computation"; partial continuations, on the other
hand, allow you to define exactly what you mean by the "current
computation". See
http://citeseer.ist.psu.edu/queinnec91dynamic.html
for a detailed, formal look at this.
I know how to implement partial continuations in Forth -- you just
copy items off of the return stack and into an array, and stop copying
when you reach the start of the partial continuation (marking the
start is a different issue, of course). How would you handle them in
XY?
-Billy
sa@dfa.com — 2004-09-23 19:52:23
"William Tanksley, Jr" <
wtanksleyjr@...> wrote on 09/23/2004 03:15:25
PM:
> On Wed, 22 Sep 2004 18:55:23 -0400, stevan apter <sa@...> wrote:
> > i've posted the "final" draft on my website:
> > www.nsl.com/k/xy/xy.htm
>
> I think you've really got something there, stevan. Your notation and
> explanations make sense, and have clarified some of the things I was
> having a hard time explaining for Forth.
thanks - i'm glad you find it helpful in this way. for me too
this has been an exercise in getting clear on certain intractably
fuzzy ideas.
>
> Now that you've mastered continuations, are you ready to take on
> partial continuations? A normal continuation allows you to use "the
> rest of the current computation"; partial continuations, on the other
> hand, allow you to define exactly what you mean by the "current
> computation". See http://citeseer.ist.psu.edu/queinnec91dynamic.html
> for a detailed, formal look at this.
formal indeed. i really should learn scheme, but every attempt
on my part to do so usually leads to my suddenly remembering that
i have something really really important to do RIGHT NOW.
>
> I know how to implement partial continuations in Forth -- you just
> copy items off of the return stack and into an array, and stop copying
> when you reach the start of the partial continuation (marking the
> start is a different issue, of course). How would you handle them in
> XY?
i've printed out the paper. i'll read through it this weekend and
let you know. it does look interesting. if you feel like describing
your Forth implementation - at least in outline - that would also
be interesting.
>
> -Billy
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
Slava Pestov — 2004-09-23 20:07:29
phimvt@... wrote:
> Thanks Stevan. I've saved it as .htm and as .txt
> We'll have to decide which format is best for the
> joint collection.
May I suggest LaTeX?
> Slava - shall I now save your Factor version?
> I did not see any comments coming.
I still intend to write a short section on continuations, and make some
minor improvements to my article. Is it OK if I send a new draft on
saturday, and if no mistakes are found, this can be the final?
Slava
Slava Pestov — 2004-09-23 20:09:39
William Tanksley, Jr wrote:
> Now that you've mastered continuations, are you ready to take on
> partial continuations? A normal continuation allows you to use "the
> rest of the current computation"; partial continuations, on the other
> hand, allow you to define exactly what you mean by the "current
> computation". See http://citeseer.ist.psu.edu/queinnec91dynamic.html
> for a detailed, formal look at this.
Can a partial continuation be approximated with a full continuation and
an exit continuation? Of course, that is potentially less efficient.
Slava
stevan apter — 2004-09-23 21:37:05
if the primary repository is the internet, then why not
html? are there disadvantages to this format i'm not
aware of?
i moved (very reluctantly) to .htm a few years ago (from
.txt). if necessary, i can manipulate the rudimentary
html i rely on in a text editor. but latex markup is
significantly more complex, isn't it? are there compensating
advantages?
----- Original Message -----
From: "Slava Pestov" <slava@...>
To: <concatenative@yahoogroups.com>
Sent: Thursday, September 23, 2004 4:07 PM
Subject: Re: [stack] XY: final draft
> phimvt@... wrote:
> > Thanks Stevan. I've saved it as .htm and as .txt
> > We'll have to decide which format is best for the
> > joint collection.
>
> May I suggest LaTeX?
>
> > Slava - shall I now save your Factor version?
> > I did not see any comments coming.
>
> I still intend to write a short section on continuations, and make some
> minor improvements to my article. Is it OK if I send a new draft on
> saturday, and if no mistakes are found, this can be the final?
>
> Slava
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
Chris Double — 2004-09-23 22:06:14
sa@dfa.com — 2004-09-24 16:00:41
the joy manual defines 'map' this way:
A [P] -> B
executes P on each member of aggregate A, collects results in aggregate B.
in fact, it appears to collect the *first element* of each result:
[1 2 3] [dup] map .
[1 2 3]
(to collect the entire result:
[1 2 3] [[] cons [dup] infra] map
or is there a better way?)
where no first element exists, joy1.exe crashes:
[1 2 3] [pop] map .
(uh oh)
in XY, 'first' (written *:) confronts an empty stack and projects:
[1 2 3] [drop] map
[[*:] [*:] [*:]]
stevan apter — 2004-09-25 16:03:49
----- Original Message -----
From: "William Tanksley, Jr" <wtanksleyjr@...>
To: <concatenative@yahoogroups.com>
Sent: Thursday, September 23, 2004 3:15 PM
Subject: Re: [stack] XY: final draft
> On Wed, 22 Sep 2004 18:55:23 -0400, stevan apter <sa@...> wrote:
> > i've posted the "final" draft on my website:
> > www.nsl.com/k/xy/xy.htm
>
> I think you've really got something there, stevan. Your notation and
> explanations make sense, and have clarified some of the things I was
> having a hard time explaining for Forth.
>
> Now that you've mastered continuations, are you ready to take on
> partial continuations? A normal continuation allows you to use "the
> rest of the current computation"; partial continuations, on the other
> hand, allow you to define exactly what you mean by the "current
> computation". See http://citeseer.ist.psu.edu/queinnec91dynamic.html
> for a detailed, formal look at this.
>
> I know how to implement partial continuations in Forth -- you just
> copy items off of the return stack and into an array, and stop copying
> when you reach the start of the partial continuation (marking the
> start is a different issue, of course). How would you handle them in
> XY?
perhaps you can tell me, since i don't understand the scheme treatment,
even after reading chris's excellent presentation.
consider a simplified version of call/cc:
; cc {{ [q] [_x _y cont/cc] q i }} ;
cc takes a quotation q and executes it on the triple consisting of the
current stack _x, the current queue _y, and the program cont/cc.
cont/cc is:
; cont/cc {{ [x y] x <- y -> }} ;
cont/cc makes x the current stack and y the current queue.
consider the following test devised by chris for factor:
; test-cc
["inside" print$ "tcc" .s] cc
"resuming" print$ ;
; call-cc
tcc
"exiting call-cc" print$ ;
test-cc
inside
resuming
tcc
resuming
call-cc
resuming
if, instead of replacing the current stack and queue with x and y,
we append x to the current stack and prepend y to the current queue:
; rc {{ [q] [_x _y cont/rc] q i }} ;
; cont/rc {{ [x y] x i y i }} ;
; test-rc
["inside" print$ "trc" .s] rc
"resuming" print$ ;
; call-rc
trc
"exiting call-rc" print$ ;
test-rc
inside
resuming
trc
resuming
call-rc
resuming
exiting call-rc <---- nb, copare with call-cc
cont/rc embeds the old stack and queue x and y in the current
stack and queue X and Y:
XXXXXXXXXxxxxxxxx yyyyyyyyyYYYYYYYYYY
as chris points out, the main reason for partial continuations
is efficiency: partial continuations are smaller than (in my
framework) the whole stack and the whole queue. but i don't
understand the principle behind 'splitter' well enough to design
something analogous for XY.
>
> -Billy
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
William Tanksley, Jr — 2004-09-26 06:11:50
On Sat, 25 Sep 2004 12:03:49 -0400, stevan apter <
sa@...> wrote:
> From: "William Tanksley, Jr" <wtanksleyjr@...>
> > Now that you've mastered continuations, are you ready to take on
> > partial continuations? A normal continuation allows you to use "the
> perhaps you can tell me, since i don't understand the scheme treatment,
> even after reading chris's excellent presentation.
I'm not sure. I don't understand what you're asking. Could you repeat
the question?
> as chris points out, the main reason for partial continuations
> is efficiency: partial continuations are smaller than (in my
> framework) the whole stack and the whole queue. but i don't
> understand the principle behind 'splitter' well enough to design
> something analogous for XY.
It's true that partial continuations take less space than full
continuations, but that's not the main reason to use them. The main
reason is that they give you so much more control. When you call a
full continuation, you transfer control to it, and it'll never return
to you (nor can it; by calling it, you replace ALL of your state with
its state). When you call a partial continuation, it's a true call:
once it's finished, it returns to you.
-Billy
phimvt@lurac.latrobe.edu.au — 2004-10-12 06:01:39
On Fri, 24 Sep 2004
sa@... wrote:
> the joy manual defines 'map' this way:
>
> A [P] -> B
> executes P on each member of aggregate A, collects results in aggregate B.
>
> in fact, it appears to collect the *first element* of each result:
>
> [1 2 3] [dup] map .
> [1 2 3]
You could also do:
[1 2 3] [] map.
[1 2 3]
> (to collect the entire result:
>
> [1 2 3] [[] cons [dup] infra] map
>
> or is there a better way?)
Maybe you want:
1 2 3 [a b c] [stack] map.
[[a 3 2 1][b 3 2 1][c 3 2 1]]
> where no first element exists, joy1.exe crashes:
>
> [1 2 3] [pop] map .
> (uh oh)
Uh oh - yes. I think you or somebody else pointed this out
quite some time ago. It got onto my to-do list but never got
done. Now it is on my will-do-I-promise list
Joy should give a runtime error, but it should not crash.
Thanks.
- Manfred
sa@dfa.com — 2004-10-12 15:09:13
phimvt@... wrote on 10/12/2004 02:01:39 AM:
>
>
> On Fri, 24 Sep 2004 sa@... wrote:
>
> > the joy manual defines 'map' this way:
> >
> > A [P] -> B
> > executes P on each member of aggregate A, collects results in aggregate
B.
> >
> > in fact, it appears to collect the *first element* of each result:
> >
> > [1 2 3] [dup] map .
> > [1 2 3]
>
> You could also do:
> [1 2 3] [] map.
> [1 2 3]
well yes - but what i half-expected from [1 2 3] [dup] map was
a duplication of each of the elements: either [1 1 2 2 3 3] or
[[1 1][2 2][3 3]].
that a single execution step can leave more than one result on
the stack is, i realize, very powerful. but i confess that i
am sometimes troubled by both it, and by another feature that
seems related; namely, that a program under the control of a
combinator can reach into the stack to any depth to get the
arguments it needs. e.g.
10 20 [3 4 5] [* +] map
.
[70 90 110]
>
> > (to collect the entire result:
> >
> > [1 2 3] [[] cons [dup] infra] map
> >
> > or is there a better way?)
>
> Maybe you want:
> 1 2 3 [a b c] [stack] map.
> [[a 3 2 1][b 3 2 1][c 3 2 1]]
>
> > where no first element exists, joy1.exe crashes:
> >
> > [1 2 3] [pop] map .
> > (uh oh)
>
> Uh oh - yes. I think you or somebody else pointed this out
> quite some time ago. It got onto my to-do list but never got
> done. Now it is on my will-do-I-promise list
> Joy should give a runtime error, but it should not crash.
> Thanks.
>
> - Manfred
>
>
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
Slava Pestov — 2004-10-17 23:32:15
sa@... wrote:
> well yes - but what i half-expected from [1 2 3] [dup] map was
> a duplication of each of the elements: either [1 1 2 2 3 3] or
> [[1 1][2 2][3 3]].
In Factor, the behavior of [ 1 2 3 ] [ dup ] map is undefined. In
practice, it will simply build a new list [ 1 2 3 ] and leave 1 2 3 on
the stack, but really its undefined.
> that a single execution step can leave more than one result on
> the stack is, i realize, very powerful. but i confess that i
> am sometimes troubled by both it, and by another feature that
> seems related; namely, that a program under the control of a
> combinator can reach into the stack to any depth to get the
> arguments it needs. e.g.
>
> 10 20 [3 4 5] [* +] map
> .
> [70 90 110]
I've never found this to be a problem. For example, to multiply every
element of a list by a constant:
: each-* ( n list -- list )
[ over * ] map nip ;
I think it is a useful technique and is easy to understand.
Slava
stevan apter — 2004-10-19 00:18:13
----- Original Message -----
From: "Slava Pestov" <slava@...>
To: <concatenative@yahoogroups.com>
Sent: Sunday, October 17, 2004 7:32 PM
Subject: Re: [stack] map
>
> sa@... wrote:
> > well yes - but what i half-expected from [1 2 3] [dup] map was
> > a duplication of each of the elements: either [1 1 2 2 3 3] or
> > [[1 1][2 2][3 3]].
>
> In Factor, the behavior of [ 1 2 3 ] [ dup ] map is undefined. In
> practice, it will simply build a new list [ 1 2 3 ] and leave 1 2 3 on
> the stack, but really its undefined.
is it? doesn't
[ 1 2 3 ] [ dup + ] map
yield
[ 2 4 6 ]
? my picture of how 'map' works is that it repeatedly places each
element of the list on the stack, evaluates the quotation, and then
appends the first item on the stack to the result-list.
Slava Pestov — 2004-10-19 00:22:26
stevan apter wrote:
> is it? doesn't
>
> [ 1 2 3 ] [ dup + ] map
>
> yield
>
> [ 2 4 6 ]
>
> ? my picture of how 'map' works is that it repeatedly places each
> element of the list on the stack, evaluates the quotation, and then
> appends the first item on the stack to the result-list.
Indeed [ 1 2 3 ] [ dup + ] map works as described, but we were
discussing [ 1 2 3 ] [ dup ] map, where [ dup ] leaves two values on the
stack, not one.
Slava
stevan apter — 2004-10-19 02:25:19
----- Original Message -----
From: "Slava Pestov" <slava@...>
To: <concatenative@yahoogroups.com>
Sent: Monday, October 18, 2004 8:22 PM
Subject: Re: [stack] map
>
> stevan apter wrote:
> > is it? doesn't
> >
> > [ 1 2 3 ] [ dup + ] map
> >
> > yield
> >
> > [ 2 4 6 ]
> >
> > ? my picture of how 'map' works is that it repeatedly places each
> > element of the list on the stack, evaluates the quotation, and then
> > appends the first item on the stack to the result-list.
>
> Indeed [ 1 2 3 ] [ dup + ] map works as described, but we were
> discussing [ 1 2 3 ] [ dup ] map, where [ dup ] leaves two values on the
> stack, not one.
what result does factor give for:
[ 1 2 3 ] [ [ ] ] map
?
>
> Slava
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
Slava Pestov — 2004-10-19 02:37:28
stevan apter wrote:
> what result does factor give for:
>
> [ 1 2 3 ] [ [ ] ] map
>
> ?
The documentation for 'map' is quite explicit:
: map ( list quot -- list )
#! Push each element of a proper list in turn, and collect
#! return values of applying a quotation with effect
#! ( X -- Y ) to each element into a new list.
over [ (each) rot >r map r> swons ] [ drop ] ifte ;
The quotation [ [ ] ] has stack effect ( -- x ) not ( x -- y ), so the
behavior is undefined.
Slava
Daniel Ehrenberg — 2004-10-19 03:04:29
> what result does factor give for:
>
> [ 1 2 3 ] [ [ ] ] map
>
> ?
Like Slava said, the result is undefined, but it
should push 1 2 and 3 on the stack and push a list of
[ [ ] [ ] [ ] ]. In XY, Factor's map might be
implemented as (this is a direct translation):
; map [] transp [
{[a b c] c b a b} [[i] dip cons] dip
] step pop |: ;
so basically it pushes each element of the list, and
for each of them it executes the quotation and
collects the top of the stack in a list. Other stack
effects can happen, and they will affect the stack;
only the top is collected. Even if the Joy way might
be slightly easier to use in some cases, this way is
more flexible and is much more efficient, at least in
the way Factor is implemented.
Daniel Ehrenberg
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
sa@dfa.com — 2004-10-19 18:43:41
thanks daniel.
you're right to say that 'map' is an application of the
'step' combinator - i hadn't seen that, and it makes for
a much simpler implementation - but the code below doesn't
quite work, at least in XY. you say that it's a direct
translation - from Factor, or L? it would be useful to
know if your code does work in some language.
Daniel Ehrenberg <
littledanehren@...> wrote on 10/18/2004 11:04:29
PM:
>
> > what result does factor give for:
> >
> > [ 1 2 3 ] [ [ ] ] map
> >
> > ?
>
> Like Slava said, the result is undefined, but it
> should push 1 2 and 3 on the stack and push a list of
> [ [ ] [ ] [ ] ]. In XY, Factor's map might be
> implemented as (this is a direct translation):
> ; map [] transp [
> {[a b c] c b a b} [[i] dip cons] dip
> ] step pop |: ;
> so basically it pushes each element of the list, and
> for each of them it executes the quotation and
> collects the top of the stack in a list. Other stack
> effects can happen, and they will affect the stack;
> only the top is collected. Even if the Joy way might
> be slightly easier to use in some cases, this way is
> more flexible and is much more efficient, at least in
> the way Factor is implemented.
>
> Daniel Ehrenberg
>
> __________________________________________________
> Do You Yahoo!?
> Tired of spam? Yahoo! Mail has the best spam protection around
> http://mail.yahoo.com
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
Slava Pestov — 2004-10-21 03:23:15
> you say that it's a direct
> translation - from Factor, or L? it would be useful to
> know if your code does work in some language.
It looks like a port of the pre-Factor 0.67 implementation of 'map' --
although its entirely possible that Daniel independently came up with
this implementation for 'map' in L.
Here is the old Factor 'map':
: map ( list quot -- list )
f transp [
transp over >r >r call r> cons r>
] each drop nreverse ;
Compare with the XY code posted by Dan:
; map
[] transp [
{[a b c] c b a b} [[i] dip cons] dip
] step pop |: ;
Nowadays Factor's 'map' is implemented as follows:
: 2slip ( quot x y -- x y ) >r >r call r> r> ;
: (each) ( list quot -- list quot )
>r uncons r> tuck 2slip ;
: map ( list quot -- list )
over [ (each) rot >r map r> swons ] [ drop ] ifte ;
Note that 2slip is a general-purpose combinator, and (each) is a helper
word shared by each, map and subset. Also note that the new
implementation is not tail-recursive. I sacrificed tail-recursiveness in
favor of eliminating the second pass over the list to reverse it, and
also to simplify the code (it allowed the common (each) word to be
introduced which made the implementation of each, map and subset shorter).
Slava
sa@dfa.com — 2004-10-22 15:37:15
Slava Pestov <
slava@...> wrote on 10/20/2004 11:23:15 PM:
>
> : map ( list quot -- list )
> over [ (each) rot >r map r> swons ] [ drop ] ifte ;
>
it took me a few minutes to realize that factor's implementation of
'ifte' differs from joy's: you expect
truth-value [P] [Q]
on the stack, where manfred expects
[truth-function] [P] [Q]
i take it that this was deliberate - but why?
anyway, this got me thinking on the ride into work today that
the most awkward combinators (for me) are 'ifte' and 'cond'.
i thought it would be nice to be able to write things like
if: 1 = then: 10 + else: if: 2 = then: 20 + else: 30 +
and, in general, to have a set of control-words with syntax
along more conventional lines:
while: .. do: ..
for: .. : do: ..
(i haven't really thought through what those should be -
suggestions welcome here.)
because XY has access to the queue, the if/then/else control
structure is easy to implement:
; if: {{ [] _x _y \then: take infra* _y \then: drop -> }} ;
; then: {{ [b] _y \else: take-drop 1 _. pair b ~: @ -> }} ;
; else: ;
'else:' is just a noise word.
'if:' works this way: it takes the if-part from the queue,
evaluates it, and takes the first element of the result. it
prepends that to the then-part, all of which becomes the new
queue.
'then:' turns the queue into [then-part else-part] and uses
the boolean result of 'if:' to index out one of the parts.
this part becomes the new queue.
sa@dfa.com — 2004-10-22 16:24:55
i see that there's a simpler implementation, in which 'then:'
and 'else:' are both noise-words:
; if: {{ [] _x _y \then: take infra* ~:
_y \then: drop \else: take-drop pair @. -> }} ;
sa@... wrote on 10/22/2004 11:37:15 AM:
>
> Slava Pestov <slava@...> wrote on 10/20/2004 11:23:15 PM:
>
> >
> > : map ( list quot -- list )
> > over [ (each) rot >r map r> swons ] [ drop ] ifte ;
> >
>
> it took me a few minutes to realize that factor's implementation of
> 'ifte' differs from joy's: you expect
>
> truth-value [P] [Q]
>
> on the stack, where manfred expects
>
> [truth-function] [P] [Q]
>
> i take it that this was deliberate - but why?
>
> anyway, this got me thinking on the ride into work today that
> the most awkward combinators (for me) are 'ifte' and 'cond'.
>
> i thought it would be nice to be able to write things like
>
> if: 1 = then: 10 + else: if: 2 = then: 20 + else: 30 +
>
> and, in general, to have a set of control-words with syntax
> along more conventional lines:
>
> while: .. do: ..
> for: .. : do: ..
>
> (i haven't really thought through what those should be -
> suggestions welcome here.)
>
> because XY has access to the queue, the if/then/else control
> structure is easy to implement:
>
> ; if: {{ [] _x _y \then: take infra* _y \then: drop -> }} ;
> ; then: {{ [b] _y \else: take-drop 1 _. pair b ~: @ -> }} ;
> ; else: ;
>
> 'else:' is just a noise word.
>
> 'if:' works this way: it takes the if-part from the queue,
> evaluates it, and takes the first element of the result. it
> prepends that to the then-part, all of which becomes the new
> queue.
>
> 'then:' turns the queue into [then-part else-part] and uses
> the boolean result of 'if:' to index out one of the parts.
> this part becomes the new queue.
>
>
>
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
Slava Pestov — 2004-10-22 17:11:29
sa@... wrote:
> it took me a few minutes to realize that factor's implementation of
> 'ifte' differs from joy's: you expect
>
> truth-value [P] [Q]
>
> on the stack, where manfred expects
>
> [truth-function] [P] [Q]
>
> i take it that this was deliberate - but why?
Joy's ifte restores the stack after executing the truth function. In
Factor this is not possible without copying the entire stack since the
stack is an array not a list.
> anyway, this got me thinking on the ride into work today that
> the most awkward combinators (for me) are 'ifte' and 'cond'.
>
> i thought it would be nice to be able to write things like
>
> if: 1 = then: 10 + else: if: 2 = then: 20 + else: 30 +
This is how its done in Forth.
Slava
sa@dfa.com — 2004-10-22 17:24:15
it would be interesting to see a document highlighting
the differences between factor and joy.
Slava Pestov <
slava@...> wrote on 10/22/2004 01:11:29 PM:
>
> sa@... wrote:
> > it took me a few minutes to realize that factor's implementation of
> > 'ifte' differs from joy's: you expect
> >
> > truth-value [P] [Q]
> >
> > on the stack, where manfred expects
> >
> > [truth-function] [P] [Q]
> >
> > i take it that this was deliberate - but why?
>
> Joy's ifte restores the stack after executing the truth function. In
> Factor this is not possible without copying the entire stack since the
> stack is an array not a list.
>
> > anyway, this got me thinking on the ride into work today that
> > the most awkward combinators (for me) are 'ifte' and 'cond'.
> >
> > i thought it would be nice to be able to write things like
> >
> > if: 1 = then: 10 + else: if: 2 = then: 20 + else: 30 +
>
> This is how its done in Forth.
>
> Slava
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
William Tanksley, Jr — 2004-10-22 19:37:45
On Fri, 22 Oct 2004 13:11:29 -0400, Slava Pestov <
slava@...> wrote:
> sa@... wrote:
> > it took me a few minutes to realize that factor's implementation of
> > 'ifte' differs from joy's: you expect
> > truth-value [P] [Q]
> > on the stack, where manfred expects
> > [truth-function] [P] [Q]
> > i take it that this was deliberate - but why?
> Joy's ifte restores the stack after executing the truth function. In
> Factor this is not possible without copying the entire stack since the
> stack is an array not a list.
To me, it makes sense to avoid quoting unconditional code -- the truth
function will always be executed, so quoting and enlisting it is
simply needless overhead.
> > anyway, this got me thinking on the ride into work today that
> > the most awkward combinators (for me) are 'ifte' and 'cond'.
> > i thought it would be nice to be able to write things like
> > if: 1 = then: 10 + else: if: 2 = then: 20 + else: 30 +
> This is how its done in Forth.
I should be writing my intro to Forth's conditionals, but I haven't
had ANY time to work on my computer at home.
The superficial syntax of Forth is kind of like what you describe,
except for the position of the IF:
dup 1 = IF 10 + ELSE dup 2 = IF 20 + ELSE 30 + ENDIF ENDIF
Deep down, though, Forth does some really funky things. IF is actually
an "immediate" word that compiles a conditional jump, but pushes the
address of the jump onto the compile-time data stack. ELSE and ENDIF
act at compile-time to take the address of a jump, and modify it to
point to themselves. (ELSE does a little more, of course.)
WHILE and the other loop words act the same. This means that all of
these words can be combined in surprising ways; it may look like IF
and ELSE are a matched pair, but WHILE and ELSE are an equally
possible combination. I've seen some bizzare tricks played with this
feature.
> Slava
-Billy
Slava Pestov — 2004-10-22 20:15:27
William Tanksley, Jr wrote:
> To me, it makes sense to avoid quoting unconditional code -- the truth
> function will always be executed, so quoting and enlisting it is
> simply needless overhead.
Restoring the stack after the condition is evaluated removes the need
for dup'ing any values before executing the condition.
> dup 1 = IF 10 + ELSE dup 2 = IF 20 + ELSE 30 + ENDIF ENDIF
s/ENDIF/THEN/ :-)
> it may look like IF
> and ELSE are a matched pair, but WHILE and ELSE are an equally
> possible combination. I've seen some bizzare tricks played with this
> feature.
This slightly worries me. The C implementation of Factor uses the same
model in the parser, and all the following code is valid:
[ 1 2 3 }
-- parses like { 1 2 3 }
CREATE hello [ "Hello world" print ;
-- parses like : hello "Hello world" print ;
I'm not sure if stronger error checking is needed.
Slava
sa@dfa.com — 2004-10-22 20:22:35
"William Tanksley, Jr" <
wtanksleyjr@...> wrote on 10/22/2004 03:37:45
PM:
>
> On Fri, 22 Oct 2004 13:11:29 -0400, Slava Pestov <slava@...> wrote:
> > sa@... wrote:
> > > it took me a few minutes to realize that factor's implementation of
> > > 'ifte' differs from joy's: you expect
> > > truth-value [P] [Q]
> > > on the stack, where manfred expects
> > > [truth-function] [P] [Q]
> > > i take it that this was deliberate - but why?
>
> > Joy's ifte restores the stack after executing the truth function. In
> > Factor this is not possible without copying the entire stack since the
> > stack is an array not a list.
>
> To me, it makes sense to avoid quoting unconditional code -- the truth
> function will always be executed, so quoting and enlisting it is
> simply needless overhead.
factor's 'ifte' (and XY's 'if', which has identical syntax/semantics)
amounts to executing the result of indexing into a pair of quotations:
pair @. i // @. is: index list -> value at index in list
e.g.
10 1 [1 +] [2 +] if
12
i think it still makes sense to have 'ifte' as it is defined in joy.
i use both to implement 'cond':
; cond {{ [a] a #: 1 = [a *: i] [a _x cond.] if }} ;
; cond. {{ [[[b T] A] x] x <- b T [A cond] ifte }} ;
manfred?
>
> > > anyway, this got me thinking on the ride into work today that
> > > the most awkward combinators (for me) are 'ifte' and 'cond'.
> > > i thought it would be nice to be able to write things like
> > > if: 1 = then: 10 + else: if: 2 = then: 20 + else: 30 +
>
> > This is how its done in Forth.
>
> I should be writing my intro to Forth's conditionals, but I haven't
> had ANY time to work on my computer at home.
the perils of procreation. :)
>
> The superficial syntax of Forth is kind of like what you describe,
> except for the position of the IF:
>
> dup 1 = IF 10 + ELSE dup 2 = IF 20 + ELSE 30 + ENDIF ENDIF
>
> Deep down, though, Forth does some really funky things. IF is actually
> an "immediate" word that compiles a conditional jump, but pushes the
> address of the jump onto the compile-time data stack. ELSE and ENDIF
> act at compile-time to take the address of a jump, and modify it to
> point to themselves. (ELSE does a little more, of course.)
>
> WHILE and the other loop words act the same. This means that all of
> these words can be combined in surprising ways; it may look like IF
> and ELSE are a matched pair, but WHILE and ELSE are an equally
> possible combination. I've seen some bizzare tricks played with this
> feature.
i don't understand Forth well enough to savor the mental torture.
but you'll agree (or maybe not) that Forth version looks "bent"
from the perspective of ordinary english.
>
> > Slava
>
> -Billy
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
Sergei Zubkov — 2004-10-22 21:08:20
On Fri, 22 Oct 2004
sa@... wrote to <
wtanksleyjr@...:
> i don't understand Forth well enough to savor the mental torture.
> but you'll agree (or maybe not) that Forth version looks "bent"
> from the perspective of ordinary english.
The Forth people have a comeback for that - they say they use "THEN" in a
different dictionary meaning ("Next in time, space, or order") from the
"normal" programmers ("In that case; accordingly").
:)
--Cubbi
William Tanksley, Jr — 2004-10-22 21:09:21
On Fri, 22 Oct 2004 16:15:27 -0400, Slava Pestov <
slava@...> wrote:
> William Tanksley, Jr wrote:
> > To me, it makes sense to avoid quoting unconditional code -- the truth
> > function will always be executed, so quoting and enlisting it is
> > simply needless overhead.
> Restoring the stack after the condition is evaluated removes the need
> for dup'ing any values before executing the condition.
This is true -- but how expensive is a DUP? And what about the times
when a DUP isn't needed?
Don't get me wrong; I admit that it's sometimes convenient. But by
default, the behavior of Forth is consistently to do the simplest,
least "clever" thing. If the programmer wants something clever, he has
to explicitly state it.
> > dup 1 = IF 10 + ELSE dup 2 = IF 20 + ELSE 30 + ENDIF ENDIF
> s/ENDIF/THEN/ :-)
You caught me! Guilty! :-) I didn't want to scare people more than I
already was.
> > it may look like IF
> > and ELSE are a matched pair, but WHILE and ELSE are an equally
> > possible combination. I've seen some bizzare tricks played with this
> > feature.
> This slightly worries me.
Why? If your semantics are clear, why should it worry you that people
are doing useful things with them?
> The C implementation of Factor uses the same
> model in the parser, and all the following code is valid:
> [ 1 2 3 }
> -- parses like { 1 2 3 }
Yes, I can see why this is discomforting. Perhaps a better solution
would be to remove the "{" and "}" words, and instead use something
like "]run" (or something that clearly conveys that it matches with
"[", but then does something additional). Sorry I can't be clearer,
but I don't know Factor.
> CREATE hello [ "Hello world" print ;
> -- parses like : hello "Hello world" print ;
I don't really see why this is uncomfortable. It's nowhere near as
"ugly" as the uses of Forth that I mentioned; but unlike the Forth
loops, this is effectively useless, so it probably won't get used.
> I'm not sure if stronger error checking is needed.
Easily done -- just have ":" drop a magic number on the compile-time
stack, and have ";" check for it.
> Slava
-Billy
William Tanksley, Jr — 2004-10-22 21:50:40
On Fri, 22 Oct 2004 16:22:35 -0400,
sa@... <
sa@...> wrote:
> i think it still makes sense to have 'ifte' as it is defined in joy.
For you, yes. For Forth, this would involve a substantial slowdown.
Interestingly, in some cases Forth's choice is actually at least as
easy -- sometimes you don't _want_ to save the information that's
being fed into the IF. I'm not claiming those times are more common,
though.
> > Deep down, though, Forth does some really funky things. IF is actually
> > an "immediate" word that compiles a conditional jump, but pushes the
> > address of the jump onto the compile-time data stack. ELSE and ENDIF
> > act at compile-time to take the address of a jump, and modify it to
> > point to themselves. (ELSE does a little more, of course.)
> i don't understand Forth well enough to savor the mental torture.
Mmmm, torture. Yes, until you savor mental torture you'll not
understand Forth. :-) Or K. I love both Forth and K.
It took me a long time to figure out Forth's compile-time versus
run-time, and so on. Knowing what I know now, I'm convinced that it's
a problem of presentation. I wish I were capable of writing something
better -- but thanks to this group, I know what the something better
would look like. It would explain Forth in terms of a concatenative
language that wasn't based on a stack; perhaps it would be a queue,
more probably it would be a string with loops (that was SUCH a cool
paper!).
> but you'll agree (or maybe not) that Forth version looks "bent"
> from the perspective of ordinary english.
I definitely do! But I think this is simply inevitable in an
imperative language, doubly so in a low level one. I don't think it's
a good sacrifice to be fancy in your syntax for "if", since "if" is a
naturally low-level operation. Consider, for example, that good object
orientation eliminates such conditionals.
-Billy
Slava Pestov — 2004-10-22 22:31:12
William Tanksley, Jr wrote:
> This is true -- but how expensive is a DUP? And what about the times
> when a DUP isn't needed?
In Joy, the stack is implemented as a linked list so dup is quite
expensive (compared to Factor or Forth dup). On the other hand,
saving/restoring the stack just requires retaining a pointer. So I think
in Joy's case, the three-quotation ifte makes the most sense.
> Yes, I can see why this is discomforting. Perhaps a better solution
> would be to remove the "{" and "}" words, and instead use something
> like "]run" (or something that clearly conveys that it matches with
> "[", but then does something additional). Sorry I can't be clearer,
> but I don't know Factor.
{ ... } is a vector literal.
> Easily done -- just have ":" drop a magic number on the compile-time
> stack, and have ";" check for it.
Yup. { and } can do this too.
Slava
Daniel Ehrenberg — 2004-10-23 02:59:25
> "if" is a
> naturally low-level operation. Consider, for
> example, that good object
> orientation eliminates such conditionals.
>
> -Billy
How does object orientation elimiate if? Smalltalk is
about as object oriented as you get, but it still has
conditionals. In what way are conditionals low-level?
Daniel Ehrenberg
__________________________________
Do you Yahoo!?
Yahoo! Mail - Helps protect you from nasty viruses.
http://promotions.yahoo.com/new_mail
Slava Pestov — 2004-10-23 03:42:36
OOP does not eliminate conditionals, it hides them in method dispatch.
Instead of
if(x)
y();
if(z)
t();
else
foo();
You have
qwax.blah();
class Quibble {
void blah() { ... };
}
class Sponge {
void blah() { ... };
}
...
In smalltalk, there are no conditionals in the language.
Instead, one passes a code block to the ifTrue/ifFalse methods of an
instance of False or True, which are defined as follows:
False>>ifFalse: alternativeBlock:
^alternativeBlock value
False>>ifTrue: alternativeBlock:
^nil
True>>ifFalse: alternativeBlock:
^nil
True>>ifTrue: alternativeBlock:
^alternativeBlock value
Daniel Ehrenberg wrote:
>>"if" is a
>>naturally low-level operation. Consider, for
>>example, that good object
>>orientation eliminates such conditionals.
>>
>>-Billy
>
>
> How does object orientation elimiate if? Smalltalk is
> about as object oriented as you get, but it still has
> conditionals. In what way are conditionals low-level?
>
> Daniel Ehrenberg
>
>
>
> __________________________________
> Do you Yahoo!?
> Yahoo! Mail - Helps protect you from nasty viruses.
> http://promotions.yahoo.com/new_mail
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
>
William Tanksley, Jr — 2004-10-23 14:53:31
Daniel Ehrenberg <
littledanehren@...> wrote:
> > "if" is a
> > naturally low-level operation. Consider, for
> > example, that good object
> > orientation eliminates such conditionals.
> How does object orientation elimiate if?
By replacing it with polymorphism. Naked 'if's in an object oriented
program are not the best sign -- they indicate the possibility of
something hacked into the program that's not really a part of the
design. (Nothing's certain, of course.)
Notice that a conditional, by definition, attempts to vary the
behavior of an object from outside of the object, which is a violation
of encapsulation.
> Smalltalk is
> about as object oriented as you get, but it still has
> conditionals. In what way are conditionals low-level?
Conditionals are a low-level feature of Smalltalk. It's not
unreasonable to use them, with caution, but if your code has them
throughout there's almost certainly something wrong with your design
-- your design SHOULD encapsulate each class's behavior within the
class itself.
> Daniel Ehrenberg
-Billy
Daniel Ehrenberg — 2004-10-23 19:20:52
I don't understand. Wouldn't the stuff after else: go
until the rest of the program, because the input queue
is unlimited?
> Slava Pestov <slava@...> wrote on 10/20/2004
> 11:23:15 PM:
>
> >
> > : map ( list quot -- list )
> > over [ (each) rot >r map r> swons ] [ drop ]
> ifte ;
> >
>
> it took me a few minutes to realize that factor's
> implementation of
> 'ifte' differs from joy's: you expect
>
> truth-value [P] [Q]
>
> on the stack, where manfred expects
>
> [truth-function] [P] [Q]
>
> i take it that this was deliberate - but why?
>
> anyway, this got me thinking on the ride into work
> today that
> the most awkward combinators (for me) are 'ifte' and
> 'cond'.
>
> i thought it would be nice to be able to write
> things like
>
> if: 1 = then: 10 + else: if: 2 = then: 20 +
> else: 30 +
>
> and, in general, to have a set of control-words with
> syntax
> along more conventional lines:
>
> while: .. do: ..
> for: .. : do: ..
>
> (i haven't really thought through what those should
> be -
> suggestions welcome here.)
>
> because XY has access to the queue, the if/then/else
> control
> structure is easy to implement:
>
> ; if: {{ [] _x _y \then: take infra* _y \then: drop
> -> }} ;
> ; then: {{ [b] _y \else: take-drop 1 _. pair b ~: @
> -> }} ;
> ; else: ;
>
> 'else:' is just a noise word.
>
> 'if:' works this way: it takes the if-part from the
> queue,
> evaluates it, and takes the first element of the
> result. it
> prepends that to the then-part, all of which becomes
> the new
> queue.
>
> 'then:' turns the queue into [then-part else-part]
> and uses
> the boolean result of 'if:' to index out one of the
> parts.
> this part becomes the new queue.
>
>
>
>
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
stevan apter — 2004-10-23 19:54:25
----- Original Message -----
From: "Daniel Ehrenberg" <littledanehren@...>
To: <concatenative@yahoogroups.com>
Sent: Saturday, October 23, 2004 3:20 PM
Subject: Re: [stack] map
>
> I don't understand. Wouldn't the stuff after else: go
> until the rest of the program, because the input queue
> is unlimited?
yes, that's right. the logic is a "hard branch" - the
flows can only be made to converge by coding it that
way, e.g. to get the effect
if: x then: y else: z
foo
you have to say
if: x then: y foo else: z foo
i don't think it would be too difficult to add another
noise word, 'fi:', to close the conditional:
if: x then: y else: if: u then: v else: w fi: fi:
foo
'if:' would then have to net-out subordinate occurrences
of 'if:' and 'fi:' to find its mate.
>
> > Slava Pestov <slava@...> wrote on 10/20/2004
> > 11:23:15 PM:
> >
> > >
> > > : map ( list quot -- list )
> > > over [ (each) rot >r map r> swons ] [ drop ]
> > ifte ;
> > >
> >
> > it took me a few minutes to realize that factor's
> > implementation of
> > 'ifte' differs from joy's: you expect
> >
> > truth-value [P] [Q]
> >
> > on the stack, where manfred expects
> >
> > [truth-function] [P] [Q]
> >
> > i take it that this was deliberate - but why?
> >
> > anyway, this got me thinking on the ride into work
> > today that
> > the most awkward combinators (for me) are 'ifte' and
> > 'cond'.
> >
> > i thought it would be nice to be able to write
> > things like
> >
> > if: 1 = then: 10 + else: if: 2 = then: 20 +
> > else: 30 +
> >
> > and, in general, to have a set of control-words with
> > syntax
> > along more conventional lines:
> >
> > while: .. do: ..
> > for: .. : do: ..
> >
> > (i haven't really thought through what those should
> > be -
> > suggestions welcome here.)
> >
> > because XY has access to the queue, the if/then/else
> > control
> > structure is easy to implement:
> >
> > ; if: {{ [] _x _y \then: take infra* _y \then: drop
> > -> }} ;
> > ; then: {{ [b] _y \else: take-drop 1 _. pair b ~: @
> > -> }} ;
> > ; else: ;
> >
> > 'else:' is just a noise word.
> >
> > 'if:' works this way: it takes the if-part from the
> > queue,
> > evaluates it, and takes the first element of the
> > result. it
> > prepends that to the then-part, all of which becomes
> > the new
> > queue.
> >
> > 'then:' turns the queue into [then-part else-part]
> > and uses
> > the boolean result of 'if:' to index out one of the
> > parts.
> > this part becomes the new queue.
> >
> >
> >
> >
>
>
> __________________________________________________
> Do You Yahoo!?
> Tired of spam? Yahoo! Mail has the best spam protection around
> http://mail.yahoo.com
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>
phimvt@lurac.latrobe.edu.au — 2004-10-25 07:05:44
On Fri, 22 Oct 2004
sa@... wrote:
>
> Slava Pestov <slava@...> wrote on 10/20/2004 11:23:15 PM:
>
> >
> > : map ( list quot -- list )
> > over [ (each) rot >r map r> swons ] [ drop ] ifte ;
> >
>
> it took me a few minutes to realize that factor's implementation of
> 'ifte' differs from joy's: you expect
>
> truth-value [P] [Q]
>
> on the stack, where manfred expects
>
> [truth-function] [P] [Q]
>
> i take it that this was deliberate - but why?
Yes, it is deliberate, for two reasons:
1. Most other languages have a (possibly complex) if-part
in their conditionals
2. At some early stage of developing Joy I had a combinator
"choice" which expected a truth value and two quotations, the
then-part and the else-part. But to compute the truth value,
the stack gets mangled in a way that is a nuisance most
of the time, especially if the required computation is
moderately complex. Sure, for simple things
[10 <] [pop "small"] [pop "big"] ifte
dup 10 < [pop "small"] [pop "big"] choice
are similar enough. and just one dup will do the trick.
But for more complex if-parts a lot of dup's or other
tricks are needed.
It so turned out that with a linked list implementation of
the stack it was not too difficult to provide ifte. I can
see that with an array implementation it would be much
harder.
> i thought it would be nice to be able to write things like
>
> if: 1 = then: 10 + else: if: 2 = then: 20 + else: 30 +
In Joy this is done (as in Lisp), with the cond combinator.
[..]
> 'then:' turns the queue into [then-part else-part] and uses
> the boolean result of 'if:' to index out one of the parts.
> this part becomes the new queue.
To build the two parts, do you have to copy what they have in
common (if they are arrays)?
- Manfred
stevan apter — 2004-10-25 10:14:52
----- Original Message -----
From: <phimvt@...>
> >
> > if: 1 = then: 10 + else: if: 2 = then: 20 + else: 30 +
>
> In Joy this is done (as in Lisp), with the cond combinator.
>
> [..]
>
> > 'then:' turns the queue into [then-part else-part] and uses
> > the boolean result of 'if:' to index out one of the parts.
> > this part becomes the new queue.
>
> To build the two parts, do you have to copy what they have in
> common (if they are arrays)?
they don't have anything in common. when 'if:' executes, the
queue is a list, namely
[1 = then: 10 + else: if: 2 = then: 20 + else: 30 +]
'if:' evaluates everything up to the first 'then:', then chops
the remaining part of the queue into a 'then' part and an 'else'
part, then selects one of those parts using the result of the
conditional and makes that part the new queue.
>
> - Manfred
>
William Tanksley, Jr — 2004-10-25 15:53:18
On Fri, 22 Oct 2004 18:31:12 -0400, Slava Pestov <
slava@...> wrote:
> William Tanksley, Jr wrote:
> > This is true -- but how expensive is a DUP? And what about the times
> > when a DUP isn't needed?
> In Joy, the stack is implemented as a linked list so dup is quite
> expensive (compared to Factor or Forth dup). On the other hand,
> saving/restoring the stack just requires retaining a pointer. So I think
> in Joy's case, the three-quotation ifte makes the most sense.
I would think that saving and restoring the stack would require a
list-copy. But no matter; the specific cost wasn't what I was talking
about; I was referring to the fact that there _is_ a cost. Forth is
built so that the language does almost nothing "by default"; there are
supposed to be no actions the language takes just as a hidden part of
operation. In this sense, restoring the stack as part of an 'if' would
be foreign to Forth.
This reasoning, of course, doesn't require anything from any language
other than Forth, except perhaps my personal ideal language. It
doesn't state that it's _bad_ to have a language do things behind the
programmer's back. And neither do I. But I do note that there are
tradeoffs involved, and either choice is reasonable, in its proper
context.
-Billy
sa@dfa.com — 2004-10-25 19:02:25
phimvt@lurac.latrobe.edu.au — 2004-10-26 05:47:20
On Mon, 25 Oct 2004, stevan apter wrote:
> From: <phimvt@...>
[..]
> > > 'then:' turns the queue into [then-part else-part] and uses
> > > the boolean result of 'if:' to index out one of the parts.
> > > this part becomes the new queue.
> >
> > To build the two parts, do you have to copy what they have in
> > common (if they are arrays)?
>
> they don't have anything in common. when 'if:' executes, the
> queue is a list, namely
>
> [1 = then: 10 + else: if: 2 = then: 20 + else: 30 +]
>
> 'if:' evaluates everything up to the first 'then:', then chops
> the remaining part of the queue into a 'then' part and an 'else'
> part, then selects one of those parts using the result of the
> conditional and makes that part the new queue.
I think I have misunderstood what your queue does. I thought
it contains all the remainder of the program - including
the (possibly very long) part that follows the conditional.
That is what I meant by the common part. To use the example,
the queue would consist of two branches:
10 + possibly long common remainder
if: 2 = then: 20 + else: 30 + possibly long common remainder
This would require the cumbersome copying of the possibly long common
remainder. But I now think what you do is this:
(10 + , if: 2 = then: 20 + else: 30 +) possibly long common remainder
where the comma separated the two branches.
In other words, your queue can contain pairs of two programs. Is this
correct?
- Manfred
phimvt@lurac.latrobe.edu.au — 2004-10-26 06:08:52
On Mon, 25 Oct 2004, William Tanksley, Jr wrote:
>
> On Fri, 22 Oct 2004 18:31:12 -0400, Slava Pestov <slava@...> wrote:
> > William Tanksley, Jr wrote:
> > > This is true -- but how expensive is a DUP? And what about the times
> > > when a DUP isn't needed?
> > In Joy, the stack is implemented as a linked list so dup is quite
> > expensive (compared to Factor or Forth dup).
No, this is not the case. Any dup just takes one new node, regardless
of what is being duped - a single number or a long list (linked list).
So any dup is as expensive as pushing a single number - very cheap.
Indeed, even if the stack were implemented as an array of consecutive
memory locations, a dup of a number and a dup of a linked list would
be cheap.
> > On the other hand,
> > saving/restoring the stack just requires retaining a pointer. So I think
> > in Joy's case, the three-quotation ifte makes the most sense.
That is correct. Saving a linked list stack con be done with
just retaing a pointer. That is what makes Joy's ifte so easy to
implement.
> I would think that saving and restoring the stack would require a
> list-copy.
No, just saving a pointer.
> But no matter; the specific cost wasn't what I was talking
> about; I was referring to the fact that there _is_ a cost. Forth is
> built so that the language does almost nothing "by default"; there are
> supposed to be no actions the language takes just as a hidden part of
> operation. In this sense, restoring the stack as part of an 'if' would
> be foreign to Forth.
>
> This reasoning, of course, doesn't require anything from any language
> other than Forth, except perhaps my personal ideal language. It
> doesn't state that it's _bad_ to have a language do things behind the
> programmer's back. And neither do I. But I do note that there are
> tradeoffs involved, and either choice is reasonable, in its proper
> context.
It would be of some interest to make the visible/invisibe boundary
a core concept in language design. Or maybe we do it already when
we speak of a virtual machine that is visible - and leave all the
invisible stuff to the implementation. Must think about that.
>
> -Billy
- Manfred
stevan apter — 2004-10-26 10:50:10
----- Original Message -----
From: <phimvt@...>
To: <concatenative@yahoogroups.com>
Sent: Tuesday, October 26, 2004 1:47 AM
Subject: Re: [stack] map
>
>
> On Mon, 25 Oct 2004, stevan apter wrote:
>
> > From: <phimvt@...>
>
> [..]
>
> > > > 'then:' turns the queue into [then-part else-part] and uses
> > > > the boolean result of 'if:' to index out one of the parts.
> > > > this part becomes the new queue.
> > >
> > > To build the two parts, do you have to copy what they have in
> > > common (if they are arrays)?
> >
> > they don't have anything in common. when 'if:' executes, the
> > queue is a list, namely
> >
> > [1 = then: 10 + else: if: 2 = then: 20 + else: 30 +]
> >
> > 'if:' evaluates everything up to the first 'then:', then chops
> > the remaining part of the queue into a 'then' part and an 'else'
> > part, then selects one of those parts using the result of the
> > conditional and makes that part the new queue.
>
> I think I have misunderstood what your queue does. I thought
> it contains all the remainder of the program - including
> the (possibly very long) part that follows the conditional.
no, you understood correctly. the queue is the totality of
the remainder of the program.
> That is what I meant by the common part. To use the example,
> the queue would consist of two branches:
> 10 + possibly long common remainder
> if: 2 = then: 20 + else: 30 + possibly long common remainder
> This would require the cumbersome copying of the possibly long common
> remainder. But I now think what you do is this:
> (10 + , if: 2 = then: 20 + else: 30 +) possibly long common remainder
> where the comma separated the two branches.
no - you had it right the first time - there is no common remainder.
if you wanted to implement such a thing, you'd have to have some way
of terminating the conditional, e.g. with 'fi:'.
> In other words, your queue can contain pairs of two programs. Is this
> correct?
>
> - Manfred
>
>
>
>
>
> Yahoo! Groups Links
>
>
>
>
>
>
>