# [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

    On Thu, 23 Sep 2004 16:09:39 -0400, "Slava Pestov" <slava@...>

    said:

     > Can a partial continuation be approximated with a full

    > continuation and an exit continuation? Of course, that is potentially less

    > efficient.

     Yes, see:

    http://www.double.co.nz/scheme/partial-continuations/partial-continuations.html

    It's a much less formal paper but discusses partial continuations and

    how they work with simple Scheme examples.

    Chris.

    --

      Chris Double

      chris.double@...

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

    http://www.theglobeandmail.com/servlet/ArticleNews/TPStory/LAC/20041025/OBIVERSON25/TPObituaries/?query=iverson

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

    >

    >

    >

    >

    >

    >

    >