# Re: [stack] three more proposals about Joy

## Louis Madon — 2000-07-01 04:49:59

    iepos@... wrote:

     >

    > Hello folks ...

    >

    > The last while, I've been thinking a bit about a few ways I would like

    > Joy to be modified. You may or may not like these ideas ...

    >

    > 1) Design the system so that the user feels free to pile tons of items

    >    onto the stack (treating it as an array). Modify the "size"

    > primitive

    >    to tell how many items are on the stack. Add a primitive "wrap"

    >    that wraps the whole stack up into a list. Make it feasible to

    >    use "call" ("i") to unwrap a list onto the stack. Modify "map" to

    >    apply a quotation directly to all the other items on the stack,

    >    instead of taking a list; thus, one could do

    >

    >      1 2 3 4 [dup *] map

    >

    >    and get

    >

    >      1 4 9 16

    >

    >    Modify several other list-oriented primitives ("first", "rest",

    > "at",

    >    "take", and others) to take things directly off the stack instead

    > of

    >    from lists.

    >

    >    Rationale: it is simpler; it eliminates the need for many "[]"s and

    >    related operators which serve no purpose.

     Would it be possible to see some before/after examples illustrating what

    you mean by features not serving any purpose?

    A basic principle of the stack is to provide a place to store/retrieve

    intermediate values as the system traverses the program function

    hierarchy. The key is ensuring that each function consumes only those

    values it really needs and returns results without disturbing any

    unconsumed values. The important word here is "value" - how can a

    function know what to consume if some values actually occupy multiple

    places (as in an unaggregated list)?

     If I understand your proposal correctly this retrieve/store semantics

    must now be done explicitly (whenever lists are involved) by using

    call/wrap. For example, say I want a function that can be given a list

    of numbers to compute their average and median:

    In Joy, I could do:

    dup average swap median

    However, in this proposal, it seems I would have to do something like:

    wrap dup [call median] dip swap [call average] dip

    unless I'm way off base, this is not simpler ...

    --

    Louis.

## Louis Madon — 2000-07-01 07:45:13

    iepos@... wrote:

     > 3) Replace Joy's "==" construct, and its friends, "LIBRA", "HIDE",

    > "IN",

    >    and "END" with a fully-fledged lambda construct. (Okay, I've

    > already

    >    mentioned this before).

    >

    >    Basically, a lambda in my notation looks like "foo\" where "foo"

    >    is any name, hitherto undefined, that the user wants to use.

    >    "foo\" can be thought of as a command that means,

    >

    >       Pop the top item off the stack and call it "foo".

    >

    >    Thus, if a user has been fiddling with the interactive interpreter,

    >    and has ended up with an interesting list or other thing on top

    >    of the stack, so interesting that he wants to give it a name, he

    >    can say "foo\", and *INSTANTLY* the system will bind the name "foo"

    >    to the item that was on the stack (which is now popped off).

    >    If the user becomes tired of that name, he can end the lambda's

    >    scope by doing "\foo".

     This could be useful. A while back during the discussion of a

    topological sort function I wrote both a Haskell and Joy version of that

    function:

    -- Haskell

    topsort [] = []

    topsort xs =

      let (es, xs') = sepEmpties in

        es ++ (topsort (map (mkDepUpd es) xs'))

      where

      mkDepUpd es = \(node, deps) -> (node, deps \\ es)

      sepEmpties  =

        let (es, xs') = partition (null . snd) xs in

          ((fst . unzip) es, xs')

    -- Joy

    topsort ==

      sepEmpties

        [null]

        [pop]

        [dupd swap mkDepUpd map topsort concat]

      ifte;

    mkDepUpd == unitlist [unpair] swoncat [setdiff pair] concat;

    sepEmpties == [second null] split [firsts] dip;

    One thing I noticed was that the 'mkDepUpd' helper function was quite a

    bit more complicated in the Joy version.  But if I had your lambda

    notation, it could be written as:

    mkDepUpd == x\ [unpair x setdiff pair];

    Thats quite a bit simpler. On the downside, I suspect it will make

    formal reasoning harder (I guess the lambdas could be automatically

    transformed to standard code though) and you have to worry about

    inadvertantly shadowing names - especially if you forgot to retire a

    binding with /foo.

     >

    >    A lambda could also be used for definitions; for instance, one

    > could

    >    define "swapd" by doing:

    >

    >      [[swap] dip]   swapd\

     Is it still a compile-time feature? (ie. I hope your not suggesting

    named definition is done at runtime).

    --

    Louis.

## stevan apter — 2000-07-01 12:53:37

    ----- Original Message -----

    From: <iepos@...>

    To: <concatenative@egroups.com>

    Sent: Friday, June 30, 2000 10:17 PM

    Subject: [stack] three more proposals about Joy

    > Hello folks ...

    >

    > The last while, I've been thinking a bit about a few ways I would like

    > Joy to be modified. You may or may not like these ideas ...

    >

    > 1) Design the system so that the user feels free to pile tons of items

    >    onto the stack (treating it as an array). Modify the "size" primitive

    >    to tell how many items are on the stack. Add a primitive "wrap"

    >    that wraps the whole stack up into a list. Make it feasible to

    >    use "call" ("i") to unwrap a list onto the stack.

        10 20 30 40 50 60 collect count

    10 20 30 40 50 60 6

    'collect' appends the enlist of the stack to the list.  'count' is

    conk's size primitive.

    > Modify "map" to

    >    apply a quotation directly to all the other items on the stack,

    >    instead of taking a list; thus, one could do

    >

    >      1 2 3 4 [dup *] map

    >

    >    and get

    >

    >      1 4 9 16

        1 2 3 4 stack [dup *] map unstack

      1 4 9 16

    >

    >    Modify several other list-oriented primitives ("first", "rest", "at",

    >    "take", and others) to take things directly off the stack instead of

    >    from lists.

    >

    >    Rationale: it is simpler; it eliminates the need for many "[]"s and

    >    related operators which serve no purpose.

    >

    > 2) Eliminate the ability to do direct introspection on quotations.

    >    This is actually a consequence of the suggestion in #1;

    >    "first", "rest", "at", "take", "size" could no longer be used to

    >    peek into a quotation, since the reformed versions fiddle with items

    >    directly on the stack instead of in quotations.

    in view of the availablility of stack and unstack (and in conk, collect

    and disperse) do you still think this is a good idea?

    >

    >    Anyhow, it might be useful for a system to have "reify" word that

    >    takes a program, and dumps a corresponding bunch of tokens onto

    >    the stack, or some other representation of the program. A system

    >    might also want to provide "compile", the complement to "reify";

    >    this would take a bunch of tokens and transform them into a program

    >    that can be manipulated with "call", "concat", "cons", and such.

    see above.

    >

    >    Rationale: allowing direct introspection of quotations seems to require

    >    the system to keep track of the exact way a user has constructed

    >    a quotation; this is bad in many circumstances. For example, imagine

    >    that the user has pushed "[2 + 3 +]" onto the stack. It would be

    >    nice if the system could internally rewrite this as "[5 +]". However,

    >    this would not be permitted if direct introspection is allowed,

    >    because the user could be relying on the quotation to stay exactly

    >    as he put it on there, as "[2 + 3 +]". (Okay, that wasn't exactly

    >    a really good example).

    :)

    >

    > 3) Replace Joy's "==" construct, and its friends, "LIBRA", "HIDE", "IN",

    >    and "END" with a fully-fledged lambda construct. (Okay, I've already

    >    mentioned this before).

    >

    >    Basically, a lambda in my notation looks like "foo\" where "foo"

    >    is any name, hitherto undefined, that the user wants to use.

    >    "foo\" can be thought of as a command that means,

    >

    >       Pop the top item off the stack and call it "foo".

    in conk, it's called 'set':

        "foo" [2 +] set

      `foo

        4 foo

       6

    >

    >    Thus, if a user has been fiddling with the interactive interpreter,

    >    and has ended up with an interesting list or other thing on top

    >    of the stack, so interesting that he wants to give it a name, he

    >    can say "foo\", and *INSTANTLY* the system will bind the name "foo"

    >    to the item that was on the stack (which is now popped off).

    >    If the user becomes tired of that name, he can end the lambda's

    >    scope by doing "\foo".

    i don't think we need lambdas to do that.  see above.

    >

    >    A lambda could also be used for definitions; for instance, one could

    >    define "swapd" by doing:

    >

    >      [[swap] dip]   swapd\

    >

    >    However, a lambda could be used for formal variables, when the items

    >    to name are not statically known. For instance, one could define

    >    "concat" using lambdas as:

    >

    >      [x\ y\ [y x]]  concat\

    >

    >    One could define a "squaring" program as

    >

    >      x\ [x] [x] *

    >

    >    Anyhow, I won't go into this anymore, since it has already been

    >    discussed quite a bit between Billy and I. One could scan through

    >    the archive of this list (and the TUNES list) for subjects containing

    >    "Lambda".

    sounds interesting - i'll have a look.

    >

    > - "iepos" (Brent Kerby)

    >

    > ------------------------------------------------------------------------

    > Visit Ancestry.com for a FREE 14-Day Trial and find your ancestors now.

    > Search over 550 million names and trace your family tree today. Click here:

    > http://click.egroups.com/1/5528/7/_/_/_/962417870/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## iepos@tunes.org — 2000-07-01 14:12:59

    > > 1) Design the system so that the user feels free to pile tons of items

    > >    onto the stack (treating it as an array). Modify the "size" primitive

    > >    to tell how many items are on the stack. Add a primitive "wrap"

    > >    that wraps the whole stack up into a list. Make it feasible to

    > >    use "call" ("i") to unwrap a list onto the stack.

    >

    >     10 20 30 40 50 60 collect count

    > 10 20 30 40 50 60 6

    >

    > 'collect' appends the enlist of the stack to the list.  'count' is

    > conk's size primitive.

     Yes... that would work. This "collect" is not exactly the same as "wrap";

    "wrap" would _replace_ the stack with a list containing its

    items, not just make a copy. Thus one could use "wrap pop" to wipe

    out the whole stack. I'd prefer it this way, because I tend to like

    "dup" to be the only primitive that does duplication (and similarly,

    "pop" to be the only primitive that does destruction). One could

    construct "collect" as

      collect == wrap dup dip

    One could also do the reverse, construct "wrap" from "collect", but

    it would be trickier, I think. One would have to use a loop with "pop":

      wrap == collect dup [count [pop] iterate] dip

    (supposing "iterate" takes a program and a number and executes the program

    that many times).

     > > 2) Eliminate the ability to do direct introspection on quotations.

    > >    This is actually a consequence of the suggestion in #1;

    > >    "first", "rest", "at", "take", "size" could no longer be used to

    > >    peek into a quotation, since the reformed versions fiddle with items

    > >    directly on the stack instead of in quotations.

    >

    > in view of the availablility of stack and unstack (and in conk, collect

    > and disperse) do you still think this is a good idea?

     Well, I still like the idea. It seems that making "map" and others

    list-oriented would just make it necessary to use "stack" and "unstack"

    (or "wrap" and "call") a lot. I still like making "map" fiddle directly

    with many items on the stack; it simplifies things.

    Of course, I don't really have a solid argument that it would really

    be simpler. This is just an idea. To be sure, one would have to

    implement a real system this way and then see if it is simpler.

    (I hope to get around to this someday :-)).

     > > 3) Replace Joy's "==" construct, and its friends, "LIBRA", "HIDE", "IN",

    > >    and "END" with a fully-fledged lambda construct. (Okay, I've already

    > >    mentioned this before).

    > >

    > >    Basically, a lambda in my notation looks like "foo\" where "foo"

    > >    is any name, hitherto undefined, that the user wants to use.

    > >    "foo\" can be thought of as a command that means,

    > >

    > >       Pop the top item off the stack and call it "foo".

    >

    > in conk, it's called 'set':

    >

    >     "foo" [2 +] set

     That's fine. I'm guessing that this "set" is not designed to use for

    formal variables. That is, you wouldn't want to do something like this:

      concat == "x" swap set "y" swap set [y x] "y" unset "x" unset

    - "iepos" (Brent Kerby)

## stevan apter — 2000-07-01 14:34:43

    if you think of the stack as a list, then it makes sense to

    add list-programming primitives to joy.  my approach has been

    to turn k, where the list primitives already exist, into a

    concatenative stack language.  (k without lambdas, that is)

    in conk, stack and unstack, and collect and disperse, are

    used to bring the stack into range for list-processing.

    for example

        1 2 3 4 stack dup * unstack

     1 4 9 16

    i.e.

        1 2 3 4

    1 2 3 4

        stack

    [1 2 3 4]

        dup

    [1 2 3 4][1 2 3 4]

        *

    [1 4 9 16]

        unstack

    1 4 9 16

    * knows how to multiply (conformable) lists.

    in fact, stack/unstack and collect/disperse are so useful

    that i've given them symbols:

        1 2 3 4 ( dup * )

    1 4 9 16

        1 2 3 4 (( dup * ))

    1 2 3 4 1 4 9 16

    in addition to atomic functions like + and * (functions which

    penetrate lists to apply to the atoms) there are pure list

    functions.  some of these are familiar, like count (size).

    others are less familar, but have proven over the course of

    35 years (yes, APL has been around that long!) to be useful

    computational building-blocks.

    for example, consider the problem of selecting items of a list

    which satisfy some condition.  you could use filter, but as we

    shall see, the k approach is more general:

      20 10 draw                (* 10 random numbers between 0 and 19 *)

    [8 7 17 17 6 14 9 9 9 8]

      dup

    [8 7 17 17 6 14 9 9 9 8] [8 7 17 17 6 14 9 9 9 8]

      10

    [8 7 17 17 6 14 9 9 9 8] [8 7 17 17 6 14 9 9 9 8] 10

      <                         (* nb: 10 < x, < is atomic *)

    [8 7 17 17 6 14 9 9 9 8] [0 0 1 1 0 1 0 0 0 0]

      where                     (* applied to a boolean vector, return true indices *)

    [8 7 17 17 6 14 9 9 9 8] [2 3 5]

      swap

    [2 3 5] [8 7 17 17 6 14 9 9 9 8]

      at                        (* use the indices to select from the list *)

    [17 17 14]

    i.e. select takes a list and a boolean function of a list and returns a list:

        select == [dup] dip i where swap at        (* L B -> M *)

        20 10 draw

    [14 8 15 12 14 18 5 17 13 10]

        [10 >] select

    8 5

    the k approach is more general than filter because 'where' applies to integer

    vectors, not just booleans:

        [0 1 2 3 4 5] where

    1 2 2 3 3 3 4 4 4 4 5 5 5 5 5

    here's another example, which corresponds roughly to sql's 'group by' clause.

        5 10 draw

    [2 3 0 0 1 1 4 4 2 1]

        dup group

    [2 3 0 0 1 1 4 4 2 1] [[0 8] [1] [2 3] [4 5 9] [6 7]]

    group takes a list L and returns a list of lists M.  the first list in M

    is the indices of the first item of L; the second list in M is the indices

    of the next unique item of L; etc.  so we can see that 2 occurs in L at

    indices 0 and 8; 3 at 1; &c.

    to get the unique items of L:

        dup [first] each

    [2 3 0 0 1 1 4 4 2 1] [[0 8] [1] [2 3] [4 5 9] [6 7]] [0 1 2 4 6]

    (nb: the unique primitive is faster)

    to get the counts:

        pop dup [count] each

    [2 3 0 0 1 1 4 4 2 1] [[0 8] [1] [2 3] [4 5 9] [6 7]] [2 1 2 3 2]

    to sum each group in the list:

        swap at

    [[2 2] [3] [0 0] [1 1 1] [4 4]]

        [0 [+] over] each

    [4 3 0 3 8]

    notice that at-indexing takes a list L and a list of lists M, and penetrates L with

    M s.t. the result is as nested as the product of the nestings of L and M.  this is

    very powerful.

    the second fragment applies the program [0 [+] over] to each item of the list of

    lists gotten through indexing.  the program [0 [+] over] starts with 0, and applies

    [+] repeatedly on its own result - intuitively, the operation of summing.

    in k, we would write this as:

        +/'x@=x

    i.e., add over each x indexed by the group of x.

    as you can see, the k expression is quite a bit more direct.  part of my work with

    conk is to gauge the further cognitive burden stack programming places on the

    programmer.  (this is my first venture into that way of thinking.)  at some point, i hope to have defined a set of sql

    building-blocks:  tables are (roughly) dictionaries of equal-length lists, &c.

## stevan apter — 2000-07-01 15:02:03

    ----- Original Message -----

    From: <iepos@...>

    To: <concatenative@egroups.com>

    Sent: Saturday, July 01, 2000 10:12 AM

    Subject: Re: [stack] three more proposals about Joy

    > > > 1) Design the system so that the user feels free to pile tons of items

    > > >    onto the stack (treating it as an array). Modify the "size" primitive

    > > >    to tell how many items are on the stack. Add a primitive "wrap"

    > > >    that wraps the whole stack up into a list. Make it feasible to

    > > >    use "call" ("i") to unwrap a list onto the stack.

    > >

    > >     10 20 30 40 50 60 collect count

    > > 10 20 30 40 50 60 6

    > >

    > > 'collect' appends the enlist of the stack to the list.  'count' is

    > > conk's size primitive.

    >

    > Yes... that would work. This "collect" is not exactly the same as "wrap";

    > "wrap" would _replace_ the stack with a list containing its

    > items, not just make a copy.

    that's called 'stack', in both conk and joy.  unstack replaces the

    stack with the top-most list on the stack.  newstack is [] unstack.

    > Thus one could use "wrap pop" to wipe

    > out the whole stack. I'd prefer it this way, because I tend to like

    > "dup" to be the only primitive that does duplication (and similarly,

    > "pop" to be the only primitive that does destruction). One could

    > construct "collect" as

    >

    >   collect == wrap dup dip

    >

    > One could also do the reverse, construct "wrap" from "collect", but

    > it would be trickier, I think. One would have to use a loop with "pop":

    >

    >   wrap == collect dup [count [pop] iterate] dip

    >

    > (supposing "iterate" takes a program and a number and executes the program

    > that many times).

    >

    > > > 2) Eliminate the ability to do direct introspection on quotations.

    > > >    This is actually a consequence of the suggestion in #1;

    > > >    "first", "rest", "at", "take", "size" could no longer be used to

    > > >    peek into a quotation, since the reformed versions fiddle with items

    > > >    directly on the stack instead of in quotations.

    > >

    > > in view of the availablility of stack and unstack (and in conk, collect

    > > and disperse) do you still think this is a good idea?

    >

    > Well, I still like the idea. It seems that making "map" and others

    > list-oriented would just make it necessary to use "stack" and "unstack"

    > (or "wrap" and "call") a lot. I still like making "map" fiddle directly

    > with many items on the stack; it simplifies things.

    if the stack was ... A B L P then how would you apply P to items of the list L?

    your proposal makes map too strong.

    >

    > Of course, I don't really have a solid argument that it would really

    > be simpler. This is just an idea. To be sure, one would have to

    > implement a real system this way and then see if it is simpler.

    > (I hope to get around to this someday :-)).

    >

    > > > 3) Replace Joy's "==" construct, and its friends, "LIBRA", "HIDE", "IN",

    > > >    and "END" with a fully-fledged lambda construct. (Okay, I've already

    > > >    mentioned this before).

    > > >

    > > >    Basically, a lambda in my notation looks like "foo\" where "foo"

    > > >    is any name, hitherto undefined, that the user wants to use.

    > > >    "foo\" can be thought of as a command that means,

    > > >

    > > >       Pop the top item off the stack and call it "foo".

    > >

    > > in conk, it's called 'set':

    > >

    > >     "foo" [2 +] set

    >

    > That's fine. I'm guessing that this "set" is not designed to use for

    > formal variables. That is, you wouldn't want to do something like this:

    right.

    >

    >   concat == "x" swap set "y" swap set [y x] "y" unset "x" unset

    >

    > - "iepos" (Brent Kerby)

    >

    >

    > ------------------------------------------------------------------------

    > Get 6 months of FREE* MSN Internet access!

    > http://click.egroups.com/1/5727/7/_/_/_/962460780/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## iepos@tunes.org — 2000-07-01 18:45:55

    > > I still like making "map" fiddle directly with many items on the stack;

    > > it simplifies things.

    >

    > if the stack was ... A B L P then how would you apply P to items of

    > the list L? your proposal makes map too strong.

     This is a very interesting question. I think I would avoid leaving things

    on the bottom of the stack (like "A" and "B") that I do not immediately

    need; instead I would arrange for them to be on the return stack, using

    "dip". But, there is an (awkward) solution to your problem[[B, if

    we really are in that situation:

      [wrap] dip2 dig2 [[call] dip map wrap] dip dip

    Here's how it would work... first, we wrap up "A" and "B" using

    "[wrap] dip2", leaving the stack as

      [A B] L P

    Next, we bring the wrapped-up "A" and "B" to the top of the stack with

    "dig2" (Joy's "rolldown"), leaving us with

      L P [A B]

    Then, we dip into the stack, since we do not need "A" and "B" now;

    so we have

      L P

    Now, we do "[call] dip", which will unwrap the list "L", because we

    need it to be unwrapped for "map" to work. Finally, we do "map",

    which modifies our unwrapped list. Then we "wrap" the list back up.

    After we are through with our "dip", we have

      L' [A B]

    Finally, we want to get "A" and "B" back into their original positions,

    so we do another "dip", leaving

      A B L'

    - "iepos" (Brent Kerby)

## stevan apter — 2000-07-03 11:45:10

    in joy, + replaces its inputs with its result:

        1 2 3 +

    1 5

    why is this better than just appending:

        1 2 3 +

    1 2 3 5

    sometimes we want this behavior, and sometimes

    not.  when we don't want this behavior, we have

    to pepper our code with dups (and dips and swaps),

    for example, when we want to select items from

    a list based on some condition on that list:

        [10 20 30 40] dup 30 > where swap at

    [10 20]

    at each point, we know the structure of the stack,

    and we know what we want the structure to be.

    i can imagine adding two constructs which might

    be useful in managing the stack.

    first, where f is a function which consumes n

    items from the stack, :f is that same function,

    except that it appends its result to the stack

    without deleting its arguments.  offhand, i can't

    think how to write : as a combinator; e.g. as

            [f] :

    remember that f can return more than a single

    result.

    my other thought, which surfaces now and then

    while programming in joy, is that i would like

    to have some way of specifying swaps, dups, and

    pops in the form of a declarative pattern.  for

    example, the arrow operator takes two lists and

    reorders the stack accordingly:

        [X Y Z W] [Z X W] ->

    obviously, this could be enhanced to include

    pattern-matching, but it seems quite powerful

    enough as it is.

## Juho Snellman — 2000-07-03 16:53:15

    On Mon, Jul 03, 2000 at 07:45:10AM -0400, stevan apter wrote:

     > first, where f is a function which consumes n

    > items from the stack, :f is that same function,

    > except that it appends its result to the stack

    > without deleting its arguments.  offhand, i can't

    > think how to write : as a combinator; e.g. as

    >

    >         [f] :

    >

    > remember that f can return more than a single

    > result.

     That looks very much like the 'nullary' combinator in Joy.

    Am I missing something?

    "

    nullary     :  [P]  ->  R

    Executes P, but no matter how many parameters this consumes,

    none are removed from the stack.

    "

     > my other thought, which surfaces now and then

    > while programming in joy, is that i would like

    > to have some way of specifying swaps, dups, and

    > pops in the form of a declarative pattern.  for

    > example, the arrow operator takes two lists and

    > reorders the stack accordingly:

    >

    >     [X Y Z W] [Z X W] ->

    >

    > obviously, this could be enhanced to include

    > pattern-matching, but it seems quite powerful

    > enough as it is.

     You mean like this?

    (* Find largest element of a list. There must be a more

     * idiomatic way for doing this... *)

    find-largest == dup first swap [ [<] nullary [swap] [] branch pop ] step;

    (* Create a list of 'n' following stack elements. *)

    ncons == [] swap [cons] times ;

    (* Take two lists. Replace the elements in the second list

     * with the corresponding elements of the first list. Destroy

     * first list.

     *

     * ['a 'b 'c] [1 0 2 0] -- ['b 'a 'c 'a]

     *)

    rearrange-list == [at] map swap pop;

    (* Take a list. Create a list of the following 'n' elements in

     * the stack ('n' being the largest value in the list).

     * Rearrange the second list, and put it's contents on top

     * of the stack.

     *)

    rearrange-stack == [find-largest] nullary 1 + [ncons reverse] cons dip

    		   rearrange-list

    		   i ;

    1 2 3 4 5 [1 0 1 0 3] rearrange-stack stack reverse;

    -> [1 4 5 4 5 2]

    But if you need to juggle the stack so much that this is useful,

    the algorithm probably needs rethinking :-)

    --

    Juho Snellman

    "C:stä on kehitetty Massachusettsin teknillisessä korkeakoulussa kieli

     nimeltä BCPL."

## Louis Madon — 2000-07-03 22:53:51

    Juho Snellman wrote:

     >

    > On Mon, Jul 03, 2000 at 07:45:10AM -0400, stevan apter wrote:

    > > first, where f is a function which consumes n

    > > items from the stack, :f is that same function,

    > > except that it appends its result to the stack

    > > without deleting its arguments.  offhand, i can't

    > > think how to write : as a combinator; e.g. as

    > >

    > >         [f] :

    > >

    > > remember that f can return more than a single

    > > result.

    >

    > That looks very much like the 'nullary' combinator in Joy.

    > Am I missing something?

    >

    > "

    > nullary     :  [P]  ->  R

    > Executes P, but no matter how many parameters this consumes,

    > none are removed from the stack.

    > "

     Its close, except nullary assumes P returns exactly one value

    (interestingly if I try running "1 [pop] nullary" I get a core dump! So

    clearly that return value is mandatory)

    I believe what Stevan intended was to let P have any number of return

    values.

     > > my other thought, which surfaces now and then

    > > while programming in joy, is that i would like

    > > to have some way of specifying swaps, dups, and

    > > pops in the form of a declarative pattern.  for

    > > example, the arrow operator takes two lists and

    > > reorders the stack accordingly:

    > >

    > >     [X Y Z W] [Z X W] ->

    > >

    > > obviously, this could be enhanced to include

    > > pattern-matching, but it seems quite powerful

    > > enough as it is.

    >

    > You mean like this?

    >

    > (* Find largest element of a list. There must be a more

    > * idiomatic way for doing this... *)

    > find-largest == dup first swap [ [<] nullary [swap] [] branch pop ]

    > step;

     How about,

    find-largest == unswons [max] fold

    (both your version and my version would fail on an empty list, so a test

    for that should ideally be added).

     > (* Create a list of 'n' following stack elements. *)

    > ncons == [] swap [cons] times ;

    >

    > (* Take two lists. Replace the elements in the second list

    > * with the corresponding elements of the first list. Destroy

    > * first list.

    > *

    > * ['a 'b 'c] [1 0 2 0] -- ['b 'a 'c 'a]

    > *)

    > rearrange-list == [at] map swap pop;

    >

    > (* Take a list. Create a list of the following 'n' elements in

    > * the stack ('n' being the largest value in the list).

    > * Rearrange the second list, and put it's contents on top

    > * of the stack.

    > *)

    > rearrange-stack == [find-largest] nullary 1 + [ncons reverse] cons dip

    >                rearrange-list

    >                i ;

    >

    > 1 2 3 4 5 [1 0 1 0 3] rearrange-stack stack reverse;

    > -> [1 4 5 4 5 2]

     Neat idea and with partial evaluation there would be no performance

    penalty either. I wonder if Brents' lambda concept could be implemented

    in standard Joy using a similar approach?

    --

    Louis.

## stevan apter — 2000-07-04 00:16:44

    ----- Original Message -----

    From: Juho Snellman <jsnell@...>

    To: <concatenative@egroups.com>

    Sent: Monday, July 03, 2000 12:53 PM

    Subject: Re: [stack] three more proposals about Joy

    > On Mon, Jul 03, 2000 at 07:45:10AM -0400, stevan apter wrote:

    > > first, where f is a function which consumes n

    > > items from the stack, :f is that same function,

    > > except that it appends its result to the stack

    > > without deleting its arguments.  offhand, i can't

    > > think how to write : as a combinator; e.g. as

    > >

    > >         [f] :

    > >

    > > remember that f can return more than a single

    > > result.

    >

    > That looks very much like the 'nullary' combinator in Joy.

    > Am I missing something?

    no - i was.  of course, you are right.

    thanks.

    >

    > "

    > nullary     :  [P]  ->  R

    > Executes P, but no matter how many parameters this consumes,

    > none are removed from the stack.

    > "

    >

## stevan apter — 2000-07-04 00:57:18

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Monday, July 03, 2000 6:53 PM

    Subject: Re: [stack] three more proposals about Joy

    > Juho Snellman wrote:

    > >

    > > On Mon, Jul 03, 2000 at 07:45:10AM -0400, stevan apter wrote:

    > > > first, where f is a function which consumes n

    > > > items from the stack, :f is that same function,

    > > > except that it appends its result to the stack

    > > > without deleting its arguments.  offhand, i can't

    > > > think how to write : as a combinator; e.g. as

    > > >

    > > >         [f] :

    > > >

    > > > remember that f can return more than a single

    > > > result.

    > >

    > > That looks very much like the 'nullary' combinator in Joy.

    > > Am I missing something?

    > >

    > > "

    > > nullary     :  [P]  ->  R

    > > Executes P, but no matter how many parameters this consumes,

    > > none are removed from the stack.

    > > "

    >

    > Its close, except nullary assumes P returns exactly one value

    > (interestingly if I try running "1 [pop] nullary" I get a core dump! So

    > clearly that return value is mandatory)

    >

    > I believe what Stevan intended was to let P have any number of return

    > values.

    oops - forgot about that one.  but yes, you're right.

    some of the joy combinators still feel unnatural.

    >

    >

    > > > my other thought, which surfaces now and then

    > > > while programming in joy, is that i would like

    > > > to have some way of specifying swaps, dups, and

    > > > pops in the form of a declarative pattern.  for

    > > > example, the arrow operator takes two lists and

    > > > reorders the stack accordingly:

    > > >

    > > >     [X Y Z W] [Z X W] ->

    > > >

    > > > obviously, this could be enhanced to include

    > > > pattern-matching, but it seems quite powerful

    > > > enough as it is.

    > >

    > > You mean like this?

    > >

    > > (* Find largest element of a list. There must be a more

    > > * idiomatic way for doing this... *)

    > > find-largest == dup first swap [ [<] nullary [swap] [] branch pop ]

    > > step;

    >

    >

    > How about,

    >

    > find-largest == unswons [max] fold

    or

        0 [max] over

    which does not fail on empties.

    >

    > (both your version and my version would fail on an empty list, so a test

    > for that should ideally be added).

    >

    >

    >

    > > (* Create a list of 'n' following stack elements. *)

    > > ncons == [] swap [cons] times ;

    > >

    > > (* Take two lists. Replace the elements in the second list

    > > * with the corresponding elements of the first list. Destroy

    > > * first list.

    > > *

    > > * ['a 'b 'c] [1 0 2 0] -- ['b 'a 'c 'a]

    > > *)

    > > rearrange-list == [at] map swap pop;

    > >

    > > (* Take a list. Create a list of the following 'n' elements in

    > > * the stack ('n' being the largest value in the list).

    > > * Rearrange the second list, and put it's contents on top

    > > * of the stack.

    > > *)

    > > rearrange-stack == [find-largest] nullary 1 + [ncons reverse] cons dip

    > >                rearrange-list

    > >                i ;

    > >

    > > 1 2 3 4 5 [1 0 1 0 3] rearrange-stack stack reverse;

    > > -> [1 4 5 4 5 2]

    >

    >

    > Neat idea and with partial evaluation there would be no performance

    > penalty either. I wonder if Brents' lambda concept could be implemented

    > in standard Joy using a similar approach?

    in the course of a long drive tonight, i thought about extending

    this to nested lists, e.g.

        [a [b c d]] [[a b][a c][a d]] ->

    the first list would require that the stack contains at least two

    items, and that the top of the stack is a list of at least three

    items.  so e.g.

        10 20 30 40 [50 60 70] [a [b c d]] [[a b][a c][a d]] ->

    10 20 30 [[40 50][40 60][40 70]]

    >

    >

    > --

    > Louis.

    >

    > ------------------------------------------------------------------------

    > Keep in touch with eGroups,

    > Keep your long distance bills lower with beMANY!

    > http://click.egroups.com/1/4120/7/_/_/_/962664509/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## Louis Madon — 2000-07-04 01:31:38

    stevan apter wrote:

     > From: Louis Madon <madonl@...>

    > > Juho Snellman wrote:

    > > >

    > > > (* Find largest element of a list. There must be a more

    > > > * idiomatic way for doing this... *)

    > > > find-largest == dup first swap [ [<] nullary [swap] [] branch pop ]

    > > > step;

    > >

    > >

    > > How about,

    > >

    > > find-largest == unswons [max] fold

    >

    > or

    >

    >     0 [max] over

    >

    > which does not fail on empties.

     same as

      0 [max] fold

    therefore over == fold (ie. obviously we're using differnt names for the

    same thing. 'fold' is the name Manfred uses)

    However, if you use 0 as the initial value it fails when the elements

    are all below zero. Moreover, it is less generic since it won't work on

    strings or other objects (whatever the 'max' function can handle which

    could be quite a variety of things in principle).

    In Haskell, there are two interesting functions called 'minBound' and

    'maxBound'.  If Joy had them you could write:

    minBound [max] fold

    which works correctly for empty lists and is completely generic.

    'minBound' returns the minimum value possible for the _inferred type_ in

    that context. So if we passed a list of integers, minBound would return

    (say) -32768, for a list of strings it would be "" etc.

    Defining such functions is not possible in Joy without adding a static

    overloading mechanism which is one of the many reasons why I believe Joy

    needs a good static type system.

    --

    Louis.

## Louis Madon — 2000-07-04 02:18:58

    stevan apter wrote:

     >

    > in the course of a long drive tonight, i thought about extending

    > this to nested lists, e.g.

     I hope you didn't cause too many accidents along the way ;-)

     >

    >     [a [b c d]] [[a b][a c][a d]] ->

    >

    > the first list would require that the stack contains at least two

    > items, and that the top of the stack is a list of at least three

    > items.  so e.g.

    >

    >     10 20 30 40 [50 60 70] [a [b c d]] [[a b][a c][a d]] ->

    > 10 20 30 [[40 50][40 60][40 70]]

     So you have a 'from' pattern and a 'to' pattern and -> rearranges data

    accordingly. This could effectively be the lambda idea though you'd need

    one additional refinement: change the 'to' pattern into a _template_

    which is instantiated using the matched input values, eg:

      [a [b c]] [a c + b] ->

      would be the same as

      unpair swap [+] dip

    though it seems (at least in this case) we're just trading stack noise

    for symbol noise.

    This is nonetheless quite interesting because we can view the 'from'

    pattern as formal variables and the 'to' template as a function body. So

    in effect lambdas can be supported in _standard_ Joy. I like that.

    --

    Louis.

## Juho Snellman — 2000-07-04 04:24:00

    On Tue, Jul 04, 2000 at 08:53:51AM +1000, Louis Madon wrote:

     > find-largest == unswons [max] fold

    >

    > (both your version and my version would fail on an empty list, so a test

    > for that should ideally be added).

     Hmm... I don't see fold in Manfred's Joy. Luckily, I think that

    uncons [max] step should work too ;-)

     > Neat idea and with partial evaluation there would be no performance

    > penalty either. I wonder if Brents' lambda concept could be implemented

    > in standard Joy using a similar approach?

     Yup. Just a bit more difficult. This seems to work, though

    I suspect there are borderline cases that fail. If you can

    stomach badly structured code, here it is:

    ---

    (* This code is only proof of concept. Please rewrite before

     * using it for anything real.

     *

     * Tested to work on standard Joy.

     *

     * A lambda is first made of a list of symbols and the stack,

     * taking the form of a dictionary-list. A quotation using

     * those symbols is given along with the lambda-dictionary to

     * do-lambda, which then recursively replaces the symbols with

     * the values.

     *)

        ncons == [] swap [cons] times;

        (* Make a dictionary out of a key list and a value list *)

        d_make == (* Add empty list below the two argument lists *)

                  [] swap [swap] dip

    	      (* Loop over keys *)

    	      [

    	         (* Get the corresponding value *)

                     [unswons] dip

    		 (* Create list containing key/value*)

    		 [] cons cons [] cons

    		 (* Add key/value to the dictionart list *)

                     swap [concat] dip

    	      ]

    	      step pop;

        (* Lookup value for key in a dictionary. If key not found,

         * return key. Not compatible with the typlib.joy dictionary

         * stuff, I think. *)

        d_look == [dup [] cons swap] dip

                  [

    		 (* Make backup copies *)

    		 [dup] dip dup first [swap] dip

    		 (* If key found, store value in list

    		  * above the dictionary. *)

    		 equal [ rest i swap [swons] dip ] [ pop ] branch

    	      ]

    	      step

    	      pop first

    	      ;

        (* Loop through all elements of a list. Add value produced

         * by dictionary lookup into the result list. If a list

         * is encountered, recurse. *)

        (* Rewrite using a recursion-combinator. Which one? *)

        apply-lambda ==

                  (* Create new list *)

                  [] swap [swap] dip

                  [

    	         [ list ]

    		 [ apply-lambda ]

    		 (* Ouch... This needs some serious looking at... *)

    		 [ [dup] dip swap d_look swap [swons] dip ]

    		 ifte

    	      ]

    	      step

    	      [reverse swons] dip

    	      ;

        (* Prepare an inital list for apply-lambda, and remove

         * the dictionary from the stack when ready. *)

        do-lambda == [] swap [swap] dip apply-lambda pop i;

        (* Take a list of symbols, and take a value from

         * the stack for each of them. *)

        make-lambda == (* Amount of variables *)

                       dup size

    	           (* Create list of 'n' values from stack *)

                       [ncons] cons dip swap

    	           (* Create a variable -> value mapping *)

    	           d_make;

    ---

    Usage:

    joy> 0 4 5 6 [ r j s ] make-lambda

    joy> [j [r s *] i -] do-lambda sr i sr;

    STACK:

      >> [5 [4 6 *] i -]

     >> 0

     STACK:

      >> -19

     >> 0

     joy>

    Sick, eh :-)

    Lambdas can of course be nested, but if two nested lambdas

    use the same formal variables, the latter's symbols would

    be substituted twice. Not that anyone would actually bother

    writing such code in Joy... This also shows, that raw

    functions on the stack are very  useful indeed.

    Stevan, does this run on conk?

    --

    Juho Snellman

    "C:stä on kehitetty Massachusettsin teknillisessä korkeakoulussa kieli

     nimeltä BCPL."

## Louis Madon — 2000-07-04 06:55:01

    Juho Snellman wrote:

     > On Tue, Jul 04, 2000 at 08:53:51AM +1000, Louis Madon wrote:

    > > find-largest == unswons [max] fold

    > >

    > > (both your version and my version would fail on an empty list, so a

    > test

    > > for that should ideally be added).

    >

    > Hmm... I don't see fold in Manfred's Joy.

     I don't think he's implemented it but it is documented in his paper

    "Atomic Programs of Joy" in the section "Combinators for Aggregate

    Types"

     > Luckily, I think that

    > uncons [max] step should work too ;-)

     Yes, interesting, that does indeed work. In fact, I can now see that

    'step' is the same as 'fold' but with the stack as the accumulating

    value. There is obviously no equivalent to this in applicative

    languages.

    With this insight, fold can be implemented simply as

    fold == swap step

    Maybe thats why Manfred didn't implement it :-)

     > > Neat idea and with partial evaluation there would be no performance

    > > penalty either. I wonder if Brents' lambda concept could be

    > implemented

    > > in standard Joy using a similar approach?

    >

    > Yup. Just a bit more difficult. This seems to work, though

    > I suspect there are borderline cases that fail. If you can

    > stomach badly structured code, here it is:

    >

    > ---

    > (* This code is only proof of concept. Please rewrite before

    > * using it for anything real.

    > *

    > * Tested to work on standard Joy.

    > *

    > * A lambda is first made of a list of symbols and the stack,

    > * taking the form of a dictionary-list. A quotation using

    > * those symbols is given along with the lambda-dictionary to

    > * do-lambda, which then recursively replaces the symbols with

    > * the values.

    > *)

    >

    >     ncons == [] swap [cons] times;

    >

    >     (* Make a dictionary out of a key list and a value list *)

    >

    >     d_make == (* Add empty list below the two argument lists *)

    >               [] swap [swap] dip

    >             (* Loop over keys *)

    >             [

    >                (* Get the corresponding value *)

    >                  [unswons] dip

    >             (* Create list containing key/value*)

    >             [] cons cons [] cons

    >             (* Add key/value to the dictionart list *)

    >                  swap [concat] dip

    >             ]

    >             step pop;

    >

    >     (* Lookup value for key in a dictionary. If key not found,

    >      * return key. Not compatible with the typlib.joy dictionary

    >      * stuff, I think. *)

    >     d_look == [dup [] cons swap] dip

    >               [

    >             (* Make backup copies *)

    >             [dup] dip dup first [swap] dip

    >             (* If key found, store value in list

    >               * above the dictionary. *)

    >             equal [ rest i swap [swons] dip ] [ pop ] branch

    >             ]

    >             step

    >             pop first

    >             ;

    >

    >     (* Loop through all elements of a list. Add value produced

    >      * by dictionary lookup into the result list. If a list

    >      * is encountered, recurse. *)

    >     (* Rewrite using a recursion-combinator. Which one? *)

    >     apply-lambda ==

    >               (* Create new list *)

    >               [] swap [swap] dip

    >               [

    >                [ list ]

    >             [ apply-lambda ]

    >             (* Ouch... This needs some serious looking at... *)

    >             [ [dup] dip swap d_look swap [swons] dip ]

    >             ifte

    >             ]

    >             step

    >             [reverse swons] dip

    >             ;

    >

    >     (* Prepare an inital list for apply-lambda, and remove

    >      * the dictionary from the stack when ready. *)

    >     do-lambda == [] swap [swap] dip apply-lambda pop i;

    >

    >     (* Take a list of symbols, and take a value from

    >      * the stack for each of them. *)

    >     make-lambda == (* Amount of variables *)

    >                    dup size

    >                  (* Create list of 'n' values from stack *)

    >                    [ncons] cons dip swap

    >                  (* Create a variable -> value mapping *)

    >                  d_make;

    >

    > ---

    >

    > Usage:

    >

    > joy> 0 4 5 6 [ r j s ] make-lambda

    > joy> [j [r s *] i -] do-lambda sr i sr;

    > STACK:

    > >> [5 [4 6 *] i -]

    > >> 0

    > STACK:

    > >> -19

    > >> 0

    > joy>

    >

    > Sick, eh :-)

     Wow! and you did that on your coffee break right? :-)

    So the '->' combinator discussed in my other message can now be

    implemented as:

    -> == [make-lambda] dip do-lambda

    Now that its clear we can have lambdas and even have an implementation

    of them it will be interesting to see just how useful they really are.

    BTW, a couple of (really) minor nits with respect to your code:

    'd_make' is already defined as 'zip', so d_make == zip

    some of the sequences you used also have definitions:

    swap [swap] dip == rollup

    [] cons == unitlist

    [] cons cons == pair

    [dup] dip == dupd

    [swap] dip == swapd

     >

    > Lambdas can of course be nested, but if two nested lambdas

    > use the same formal variables, the latter's symbols would

    > be substituted twice. Not that anyone would actually bother

    > writing such code in Joy... This also shows, that raw

    > functions on the stack are very  useful indeed.

     I fully agree.

    --

    Louis.

## Louis Madon — 2000-07-04 08:15:52

    Louis Madon wrote:

     > So the '->' combinator discussed in my other message can now be

    > implemented as:

    >

    > -> == [make-lambda] dip do-lambda

     Oops, there should be an 'i' on the end of that, ie.

    -> == [make-lambda] dip do-lambda i

    I just tried using it to rewrite the 'mkDepUpd' helper function in my

    topsort routine:

    (* original *)

    mkDepUpd == unitlist [unpair] swoncat [setdiff pair] concat;

    (* rewrite  *)

    mkDepUpd == [x] [[unpair x setdiff pair]] ->;

    It works beautifully and is clearly simpler than the original. (BTW I

    actually used the name 'lambda' rather than '->' since standard Joy

    complains about the syntax).

    --

    Louis.

## stevan apter — 2000-07-04 13:47:56

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Monday, July 03, 2000 9:31 PM

    Subject: Re: [stack] three more proposals about Joy

    > stevan apter wrote:

    > > From: Louis Madon <madonl@...>

    > > > Juho Snellman wrote:

    > > > >

    > > > > (* Find largest element of a list. There must be a more

    > > > > * idiomatic way for doing this... *)

    > > > > find-largest == dup first swap [ [<] nullary [swap] [] branch pop ]

    > > > > step;

    > > >

    > > >

    > > > How about,

    > > >

    > > > find-largest == unswons [max] fold

    > >

    > > or

    > >

    > >     0 [max] over

    > >

    > > which does not fail on empties.

    >

    > same as

    >

    >   0 [max] fold

    >

    > therefore over == fold (ie. obviously we're using differnt names for the

    > same thing. 'fold' is the name Manfred uses)

    fold is over restricted to binary functions.  over takes a function of

    any arity > 1:

          [[40 50 60][70 80 90]]0[* +] scan

    [0 70 3580 214890]

         [[40 50 60][70 80 90]]0[* +] scan

    [0 70 3580 214890]

    >

    > However, if you use 0 as the initial value it fails when the elements

    > are all below zero.

    ?

        [-1 -2 -3 -4] 0 [max] over

    0

    unless you want the result to always be drawn from the list:

        [-1 -2 -3 -4] 0N [max] over

    -1

    where 0N is minint.

    > Moreover, it is less generic since it won't work on

    > strings or other objects (whatever the 'max' function can handle which

    > could be quite a variety of things in principle).

    when this is a concern, the initial value should be computed from

    the type of the argument(s).

        "abcdef" 0 [max] over

    'f

    >

    > In Haskell, there are two interesting functions called 'minBound' and

    > 'maxBound'.  If Joy had them you could write:

    >

    > minBound [max] fold

    >

    > which works correctly for empty lists and is completely generic.

    > 'minBound' returns the minimum value possible for the _inferred type_ in

    > that context. So if we passed a list of integers, minBound would return

    > (say) -32768, for a list of strings it would be "" etc.

    right.

    >

    > Defining such functions is not possible in Joy without adding a static

    > overloading mechanism which is one of the many reasons why I believe Joy

    > needs a good static type system.

    >

    >

    > --

    > Louis.

    >

    > ------------------------------------------------------------------------

    > Free, Unlimited Calls Anywhere!

    > Conference in the whole family on the same call.

    > Let the fights begin!  Visit Firetalk.com - Click below.

    > http://click.egroups.com/1/5476/7/_/_/_/962673982/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## stevan apter — 2000-07-04 13:56:43

    ----- Original Message -----

    From: Juho Snellman <jsnell@...>

    To: <concatenative@egroups.com>

    Sent: Tuesday, July 04, 2000 12:24 AM

    Subject: Re: [stack] three more proposals about Joy

    > On Tue, Jul 04, 2000 at 08:53:51AM +1000, Louis Madon wrote:

    > > find-largest == unswons [max] fold

    > >

    > > (both your version and my version would fail on an empty list, so a test

    > > for that should ideally be added).

    >

    > Hmm... I don't see fold in Manfred's Joy. Luckily, I think that

    > uncons [max] step should work too ;-)

    >

    > > Neat idea and with partial evaluation there would be no performance

    > > penalty either. I wonder if Brents' lambda concept could be implemented

    > > in standard Joy using a similar approach?

    >

    > Yup. Just a bit more difficult. This seems to work, though

    > I suspect there are borderline cases that fail. If you can

    > stomach badly structured code, here it is:

    >

    > ---

    > (* This code is only proof of concept. Please rewrite before

    >  * using it for anything real.

    >  *

    >  * Tested to work on standard Joy.

    >  *

    >  * A lambda is first made of a list of symbols and the stack,

    >  * taking the form of a dictionary-list. A quotation using

    >  * those symbols is given along with the lambda-dictionary to

    >  * do-lambda, which then recursively replaces the symbols with

    >  * the values.

    >  *)

    >

    >     ncons == [] swap [cons] times;

    >

    >     (* Make a dictionary out of a key list and a value list *)

    >

    >     d_make == (* Add empty list below the two argument lists *)

    >               [] swap [swap] dip

    >       (* Loop over keys *)

    >       [

    >          (* Get the corresponding value *)

    >                  [unswons] dip

    > (* Create list containing key/value*)

    > [] cons cons [] cons

    > (* Add key/value to the dictionart list *)

    >                  swap [concat] dip

    >       ]

    >       step pop;

    >

    >     (* Lookup value for key in a dictionary. If key not found,

    >      * return key. Not compatible with the typlib.joy dictionary

    >      * stuff, I think. *)

    >     d_look == [dup [] cons swap] dip

    >

    > (* Make backup copies *)

    > [dup] dip dup first [swap] dip

    > (* If key found, store value in list

    >   * above the dictionary. *)

    > equal [ rest i swap [swons] dip ] [ pop ] branch

    >       ]

    >       step

    >       pop first

    >       ;

    >

    >     (* Loop through all elements of a list. Add value produced

    >      * by dictionary lookup into the result list. If a list

    >      * is encountered, recurse. *)

    >     (* Rewrite using a recursion-combinator. Which one? *)

    >     apply-lambda ==

    >               (* Create new list *)

    >               [] swap [swap] dip

    >               [

    >          [ list ]

    > [ apply-lambda ]

    > (* Ouch... This needs some serious looking at... *)

    > [ [dup] dip swap d_look swap [swons] dip ]

    > ifte

    >       ]

    >       step

    >       [reverse swons] dip

    >       ;

    >

    >     (* Prepare an inital list for apply-lambda, and remove

    >      * the dictionary from the stack when ready. *)

    >     do-lambda == [] swap [swap] dip apply-lambda pop i;

    >

    >     (* Take a list of symbols, and take a value from

    >      * the stack for each of them. *)

    >     make-lambda == (* Amount of variables *)

    >                    dup size

    >            (* Create list of 'n' values from stack *)

    >                    [ncons] cons dip swap

    >            (* Create a variable -> value mapping *)

    >            d_make;

    >

    > ---

    >

    > Usage:

    >

    > joy> 0 4 5 6 [ r j s ] make-lambda

    > joy> [j [r s *] i -] do-lambda sr i sr;

    > STACK:

    >  >> [5 [4 6 *] i -]

    >  >> 0

    > STACK:

    >  >> -19

    >  >> 0

    > joy>

    >

    > Sick, eh :-)

    >

    > Lambdas can of course be nested, but if two nested lambdas

    > use the same formal variables, the latter's symbols would

    > be substituted twice. Not that anyone would actually bother

    > writing such code in Joy... This also shows, that raw

    > functions on the stack are very  useful indeed.

    >

    > Stevan, does this run on conk?

    with some fiddling, it should.  currently, joy-according-to-the-

    manual and conk diverge in certain areas, so i wouldn't expect

    anything but the simplest joy code to run without modification.

    this hasn't been a problem up til now, because we've avoided

    code with as much detail as yours above.  the lambda topic is

    interesting, though.

    >

    > --

    > Juho Snellman

    > "C:stä on kehitetty Massachusettsin teknillisessä korkeakoulussa kieli

    >  nimeltä BCPL."

    >

    > ------------------------------------------------------------------------

    > 0% Introductory APR!

    > Instant Approval!

    > Aria Visa - get yours today.

    > http://click.egroups.com/1/6035/7/_/_/_/962684642/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## Juho Snellman — 2000-07-04 13:59:36

    On Tue, Jul 04, 2000 at 04:55:01PM +1000, Louis Madon wrote:

     > > Sick, eh :-)

    >

    > Wow! and you did that on your coffee break right? :-)

     Uhh... "But this is vital for my work, Boss!" ;-)

     > Now that its clear we can have lambdas and even have an implementation

    > of them it will be interesting to see just how useful they really are.

     I'm guessing, that they'll be mainly good for mathematical stuff.

    Heavy equations are hard to do without lots of juggling. However,

    for normal use the lambdas are a bad idea, IMHO. By using them,

    the easy refactoring advantage is lost, since we again need to

    worry about scope.

     > BTW, a couple of (really) minor nits with respect to your code:

    >

    > 'd_make' is already defined as 'zip', so d_make == zip

     You. Actually, I noticed that d_make wasn't even needed

    with some rewriting. I also fixed apply-lambda to use map,

    which makes it and do-lambda actually pretty.

     > some of the sequences you used also have definitions:

    >

    > swap [swap] dip == rollup

    > [] cons == unitlist

    > [] cons cons == pair

     Ah, I had totally forgot these. Thanks :-)

     > [dup] dip == dupd

    > [swap] dip == swapd

     While I think that these are better expressed using the original,

    or more expressive names. So I proabably won't use them much.

    But here is a better version:

    ---

    (* Tested to work on standard Joy.

     *

     * A lambda is first made of a list of symbols and the stack,

     * taking the form of a dictionary-list. A quotation using

     * those symbols is given along with the lambda-dictionary to

     * do-lambda, which then recursively replaces the symbols with

     * the values.

     *)

        (* Initialize result-list with key *)

        d_look_init_list == [dup unitlist swap] dip;

        (* Lookup value for key in a dictionary. If key not found,

         * return key. Not compatible with the typlib.joy dictionary

         * stuff, I think. *)

        d_look == d_look_init_list

                  [

    	         (* Unpack dictionary pair *)

    	         unpair rollup

    		 (* If key found, store value in result-list *)

    		 [equal] [ pop [swons] dip ] [pop swap pop] ifte

    	      ]

    	      step

    	      pop first;

        (* Replace all elements with the results of a dictionary

         * lookup for that element. If a list is encountered,

         * recurse. *)

        apply-lambda == [

    	              [ list ]

    		      [ apply-lambda ]

    		      [ swap [d_look] nullary ]

    		      ifte

    		    ]

    	      	    map;

        (* Do an apply-lambda, and remove the dictinary when ready. *)

        do-lambda == apply-lambda swap pop;

        (* Loop through a reverse list of symbols, take the top

         * value from the stack for each of them, and create

         * a dictionary out of it. *)

        make-lambda == reverse

                       [] swap

    		   [ swap [swap pair] dip cons ] step;

    ---

    --

    Juho Snellman

    "C:stä on kehitetty Massachusettsin teknillisessä korkeakoulussa kieli

     nimeltä BCPL."

## stevan apter — 2000-07-04 14:14:00

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Tuesday, July 04, 2000 2:55 AM

    Subject: Re: [stack] three more proposals about Joy

    >

    > With this insight, fold can be implemented simply as

    >

    > fold == swap step

        fold == [swap] dip step

    or are assuming different stack setups?

        [10 20 30 40 50] 0 [max] fold

    50

## stevan apter — 2000-07-04 15:23:04

    no surprise, but this won't run in conk, even after i make

    the obvious substitutions.  i want to align conk with joy,

    now that we have some interesting new code to play with.

    juho, can you provide one or two simple examples for this?

     ----- Original Message -----

    From: Juho Snellman <jsnell@...>

    To: <concatenative@egroups.com>

    Sent: Tuesday, July 04, 2000 9:59 AM

    Subject: Re: [stack] three more proposals about Joy

    > On Tue, Jul 04, 2000 at 04:55:01PM +1000, Louis Madon wrote:

    > > > Sick, eh :-)

    > >

    > > Wow! and you did that on your coffee break right? :-)

    >

    > Uhh... "But this is vital for my work, Boss!" ;-)

    >

    > > Now that its clear we can have lambdas and even have an implementation

    > > of them it will be interesting to see just how useful they really are.

    >

    > I'm guessing, that they'll be mainly good for mathematical stuff.

    > Heavy equations are hard to do without lots of juggling. However,

    > for normal use the lambdas are a bad idea, IMHO. By using them,

    > the easy refactoring advantage is lost, since we again need to

    > worry about scope.

    >

    > > BTW, a couple of (really) minor nits with respect to your code:

    > >

    > > 'd_make' is already defined as 'zip', so d_make == zip

    >

    > You. Actually, I noticed that d_make wasn't even needed

    > with some rewriting. I also fixed apply-lambda to use map,

    > which makes it and do-lambda actually pretty.

    >

    > > some of the sequences you used also have definitions:

    > >

    > > swap [swap] dip == rollup

    > > [] cons == unitlist

    > > [] cons cons == pair

    >

    > Ah, I had totally forgot these. Thanks :-)

    >

    > > [dup] dip == dupd

    > > [swap] dip == swapd

    >

    > While I think that these are better expressed using the original,

    > or more expressive names. So I proabably won't use them much.

    >

    > But here is a better version:

    >

    > ---

    >

    > (* Tested to work on standard Joy.

    >  *

    >  * A lambda is first made of a list of symbols and the stack,

    >  * taking the form of a dictionary-list. A quotation using

    >  * those symbols is given along with the lambda-dictionary to

    >  * do-lambda, which then recursively replaces the symbols with

    >  * the values.

    >  *)

    >

    >     (* Initialize result-list with key *)

    >     d_look_init_list == [dup unitlist swap] dip;

    >

    >     (* Lookup value for key in a dictionary. If key not found,

    >      * return key. Not compatible with the typlib.joy dictionary

    >      * stuff, I think. *)

    >     d_look == d_look_init_list

    >

    >          (* Unpack dictionary pair *)

    >          unpair rollup

    > (* If key found, store value in result-list *)

    > [equal] [ pop [swons] dip ] [pop swap pop] ifte

    >       ]

    >       step

    >       pop first;

    >

    >     (* Replace all elements with the results of a dictionary

    >      * lookup for that element. If a list is encountered,

    >      * recurse. *)

    >     apply-lambda == [

    >               [ list ]

    >       [ apply-lambda ]

    >       [ swap [d_look] nullary ]

    >       ifte

    >     ]

    >           map;

    >

    >     (* Do an apply-lambda, and remove the dictinary when ready. *)

    >     do-lambda == apply-lambda swap pop;

    >

    >     (* Loop through a reverse list of symbols, take the top

    >      * value from the stack for each of them, and create

    >      * a dictionary out of it. *)

    >     make-lambda == reverse

    >                    [] swap

    >    [ swap [swap pair] dip cons ] step;

    >

    > ---

    >

    > --

    > Juho Snellman

    > "C:stä on kehitetty Massachusettsin teknillisessä korkeakoulussa kieli

    >  nimeltä BCPL."

    >

    > ------------------------------------------------------------------------

    > Free, Unlimited Calls Anywhere!

    > Visit Firetalk.com - click below.

    > http://click.egroups.com/1/5479/7/_/_/_/962719179/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## stevan apter — 2000-07-04 18:26:35

    got it.  very nice - and you handle nested 'from' templates.

    i don't handle dashes in names, so a little renaming was necessary.

    --

    d_look_init_list == [dup unitlist swap] dip;

    d_look ==

     d_look_init_list

     [

      unpair rollup

      [equal] [ pop [swons] dip ] [pop swap pop] ifte

     ] step

     pop first;

    apply_lambda ==

     [

      [list]

      [apply_lambda]

      [swap [d_look] nullary]

      ifte

     ] map;

    do_lambda == apply_lambda swap pop;

    make_lambda ==

     reverse [] swap

     [

      swap [swap pair] dip cons

     ] step;

    ld == [make_lambda] dip do_lambda;

    conk ..

      "lambda" load

    [d_look_init_list d_look apply_lambda do_lambda make_lambda ld]

      ()

      10 20 30 [x y z][x y +] ld

    [10 20 add]

      i

    30

      ()

      10 [20 30][40 50][[x][y]] [x y +] ->

    [20 30] [40 50] [20 40 add]

## stevan apter — 2000-07-04 19:23:07

    ----- Original Message -----

    From: stevan apter <apter@...>

    To: <concatenative@egroups.com>

    Sent: Tuesday, July 04, 2000 2:26 PM

    Subject: Re: [stack] three more proposals about Joy

    > got it.  very nice - and you handle nested 'from' templates.

    :

    >

    >   10 [20 30][40 50][[x][y]] [x y +] ->

    > [20 30] [40 50] [20 40 add]

    my mistake - it doesn't appear to (that's my k implementation above).

    is your stuff supposed to understand templates like [[x][y]]?

    >

    >

    > ------------------------------------------------------------------------

    > Free Conference Calling with Firetalk!

    > Click Here!

    > http://click.egroups.com/1/5480/7/_/_/_/962734646/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## Louis Madon — 2000-07-04 21:03:09

    stevan apter wrote:

     > fold is over restricted to binary functions.  over takes a function of

    > any arity > 1:

    >

    >       [[40 50 60][70 80 90]]0[* +] scan

    > [0 70 3580 214890]

    >      [[40 50 60][70 80 90]]0[* +] scan

    > [0 70 3580 214890]

     Oh Ok, thats useful.

     >

    > >

    > > However, if you use 0 as the initial value it fails when the

    > elements

    > > are all below zero.

    >

    > ?

    >

    >     [-1 -2 -3 -4] 0 [max] over

    > 0

     Sorry I was thinking of 'min' - my whole message was probably confusing

    as a result.

     >

    > unless you want the result to always be drawn from the list:

    >

    >     [-1 -2 -3 -4] 0N [max] over

    > -1

     No I had meant the minimum, nonetheless passing minint will work for

    integers.

     > where 0N is minint.

    >

    > > Moreover, it is less generic since it won't work on

    > > strings or other objects (whatever the 'max' function can handle

    > which

    > > could be quite a variety of things in principle).

    >

    > when this is a concern, the initial value should be computed from

    > the type of the argument(s).

    >

    >     "abcdef" 0 [max] over

    > 'f

     I don't follow, you're still using 0 as the initial value, what if I do:

    ["the" "quick" "brown" "fox"] 0 [min] over

    will that return "brown" ?

## Louis Madon — 2000-07-04 21:05:32

    stevan apter wrote:

     >

    > ----- Original Message -----

    > From: Louis Madon <madonl@...>

    > To: <concatenative@egroups.com>

    > Sent: Tuesday, July 04, 2000 2:55 AM

    > Subject: Re: [stack] three more proposals about Joy

    >

    > >

    > > With this insight, fold can be implemented simply as

    > >

    > > fold == swap step

    >

    >     fold == [swap] dip step

    >

    > or are assuming different stack setups?

    >

    >     [10 20 30 40 50] 0 [max] fold

    > 50

    >

     Oh ofcourse, you are right. Thats what can happen when you spend a whole

    of three seconds writing code :-)

    --

    Louis.

## stevan apter — 2000-07-04 22:02:09

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Tuesday, July 04, 2000 5:03 PM

    Subject: Re: [stack] three more proposals about Joy

    > >

    > > when this is a concern, the initial value should be computed from

    > > the type of the argument(s).

    > >

    > >     "abcdef" 0 [max] over

    > > 'f

    >

    > I don't follow, you're still using 0 as the initial value,

            "abcdef" 0 [max] scan

    [0 'a 'b 'c 'd 'e 'f]

    a is greater than 0, b is greater than a, ... f is the greatest.

    > what if I do:

    >

    > ["the" "quick" "brown" "fox"] 0 [min] over

    >

    > will that return "brown" ?

    no - the strings differ in length, so you can't compare them.

    >

    > ------------------------------------------------------------------------

    > Free Conference Calling with Firetalk!

    > Host your next egroup meeting live on Firetalk.

    > Click here!

    > http://click.egroups.com/1/5478/7/_/_/_/962744265/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## Louis Madon — 2000-07-04 22:12:09

    stevan apter wrote:

     > > what if I do:

    > >

    > > ["the" "quick" "brown" "fox"] 0 [min] over

    > >

    > > will that return "brown" ?

    >

    > no - the strings differ in length, so you can't compare them.

     Ok, that was my point - you've lost some genericity. So you'll need

    separate functions for 'find_largest_string', 'find_largest_vector',

    etc.

    --

    Louis.

## stevan apter — 2000-07-04 22:26:26

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Tuesday, July 04, 2000 6:12 PM

    Subject: Re: [stack] three more proposals about Joy

    > stevan apter wrote:

    > > > what if I do:

    > > >

    > > > ["the" "quick" "brown" "fox"] 0 [min] over

    > > >

    > > > will that return "brown" ?

    > >

    > > no - the strings differ in length, so you can't compare them.

    >

    > Ok, that was my point - you've lost some genericity. So you'll need

    > separate functions for 'find_largest_string', 'find_largest_vector',

    > etc.

    but max is an atomic function, so it doesn't make sense to

    ask for the max of strings of different length.

    >

    >

    > --

    > Louis.

    >

    > ------------------------------------------------------------------------

    > Get 6 months of FREE* MSN Internet access!

    > http://click.egroups.com/1/5727/7/_/_/_/962748405/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## Louis Madon — 2000-07-04 22:46:37

    stevan apter wrote:

     >

    > ----- Original Message -----

    > From: Louis Madon <madonl@...>

    > To: <concatenative@egroups.com>

    > Sent: Tuesday, July 04, 2000 6:12 PM

    > Subject: Re: [stack] three more proposals about Joy

    >

    > > stevan apter wrote:

    > > > > what if I do:

    > > > >

    > > > > ["the" "quick" "brown" "fox"] 0 [min] over

    > > > >

    > > > > will that return "brown" ?

    > > >

    > > > no - the strings differ in length, so you can't compare them.

    > >

    > > Ok, that was my point - you've lost some genericity. So you'll need

    > > separate functions for 'find_largest_string', 'find_largest_vector',

    > > etc.

    >

    > but max is an atomic function, so it doesn't make sense to

    > ask for the max of strings of different length.

    >

     I really wonder why though. '<' is polymorphic and max can be trivially

    defined in terms of it:

    max == [<] [popd] [pop] ifte

    In general, it makes sense for max/min to be defined on any type that

    has a total order.

    --

    Louis.

## Juho Snellman — 2000-07-04 22:42:26

    On Tue, Jul 04, 2000 at 03:23:07PM -0400, stevan apter wrote:

     > From: stevan apter <apter@...>

    > > got it.  very nice - and you handle nested 'from' templates.

    > :

    > >

    > >   10 [20 30][40 50][[x][y]] [x y +] ->

    > > [20 30] [40 50] [20 40 add]

    >

    > my mistake - it doesn't appear to (that's my k implementation above).

    > is your stuff supposed to understand templates like [[x][y]]?

     Nope, didn't even think of that. I believe this does what

    you mean (except that it eats the arguments, unlike your

    version):

    ---

        (* Helpers *)

        get_value == [ [unswons] dip ] dip;

        add_pair == rolldown pair swons;

        remove_list == popd;

        (* Add the first and third elements from the top of

         * the stack as a key/value pair into the list that

         * is the second element. If first element is list,

         * assume third element is also a list with at least

         * as many elements and recurse. *)

        d_add ==

                 [ list ]

                 [ [ get_value d_add ] step remove_list]

    	     [ add_pair ]

    	     ifte;

        (* Loop through a reverse list of symbols, take the top

         * value from the stack for each of them, and create

         * a dictionary out of it. *)

        make-lambda == reverse

                       [] swap

    		   [ d_add ] step ;

    ---

    joy> newstack 0  [1 [2 3] 4] 5  [[a [b x] c] d]  make-lambda sr;

    STACK:

      >> [[c 4] [x 3] [b 2] [a 1] [d 5]]

     >> 0

     --

    Juho Snellman

    "C:stä on kehitetty Massachusettsin teknillisessä korkeakoulussa kieli

     nimeltä BCPL."

## stevan apter — 2000-07-04 23:36:03

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Tuesday, July 04, 2000 6:46 PM

    Subject: Re: [stack] three more proposals about Joy

    > stevan apter wrote:

    > >

    > > ----- Original Message -----

    > > From: Louis Madon <madonl@...>

    > > To: <concatenative@egroups.com>

    > > Sent: Tuesday, July 04, 2000 6:12 PM

    > > Subject: Re: [stack] three more proposals about Joy

    > >

    > > > stevan apter wrote:

    > > > > > what if I do:

    > > > > >

    > > > > > ["the" "quick" "brown" "fox"] 0 [min] over

    > > > > >

    > > > > > will that return "brown" ?

    > > > >

    > > > > no - the strings differ in length, so you can't compare them.

    > > >

    > > > Ok, that was my point - you've lost some genericity. So you'll need

    > > > separate functions for 'find_largest_string', 'find_largest_vector',

    > > > etc.

    > >

    > > but max is an atomic function, so it doesn't make sense to

    > > ask for the max of strings of different length.

    > >

    >

    > I really wonder why though. '<' is polymorphic and max can be trivially

    > defined in terms of it:

    >

    > max == [<] [popd] [pop] ifte

    >

    >

    > In general, it makes sense for max/min to be defined on any type that

    > has a total order.

    i think what we have here is a failure to communictae.  ;-)

    as in k above, so in conk below:  a string is a list of characters:

      ['a 'b 'c 'd]

    "abcd"

      first

    'a

    more precisely, "abcdef" is "vector notation" for the list of length

    six whose first element is the atom 'a, &c.

    since max and > are atomic operations, they require that their operands

    are conformable.  that's why

        "abcd" 'b >

    [1 0 0 0]

    (remember - x y > means:  y > x, not x > y).

    and

        "abcd" 'b max

    "bbcd"

    >

    >

    > --

    > Louis.

    >

    > ------------------------------------------------------------------------

    > Need a credit card?

    > Instant Approval and 0% intro APR with Aria!

    > http://click.egroups.com/1/6034/7/_/_/_/962750481/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## Louis Madon — 2000-07-05 00:01:39

    stevan apter wrote:

     >

    > ----- Original Message -----

    > From: Louis Madon <madonl@...>

    > To: <concatenative@egroups.com>

    > Sent: Tuesday, July 04, 2000 6:46 PM

    > Subject: Re: [stack] three more proposals about Joy

    >

    > > stevan apter wrote:

    > > >

    > > > ----- Original Message -----

    > > > From: Louis Madon <madonl@...>

    > > > To: <concatenative@egroups.com>

    > > > Sent: Tuesday, July 04, 2000 6:12 PM

    > > > Subject: Re: [stack] three more proposals about Joy

    > > >

    > > > > stevan apter wrote:

    > > > > > > what if I do:

    > > > > > >

    > > > > > > ["the" "quick" "brown" "fox"] 0 [min] over

    > > > > > >

    > > > > > > will that return "brown" ?

    > > > > >

    > > > > > no - the strings differ in length, so you can't compare them.

    > > > >

    > > > > Ok, that was my point - you've lost some genericity. So you'll

    > need

    > > > > separate functions for 'find_largest_string',

    > 'find_largest_vector',

    > > > > etc.

    > > >

    > > > but max is an atomic function, so it doesn't make sense to

    > > > ask for the max of strings of different length.

    > > >

    > >

    > > I really wonder why though. '<' is polymorphic and max can be

    > trivially

    > > defined in terms of it:

    > >

    > > max == [<] [popd] [pop] ifte

    > >

    > >

    > > In general, it makes sense for max/min to be defined on any type

    > that

    > > has a total order.

    >

    > i think what we have here is a failure to communictae.  ;-)

     unfortunately, the link still seems to be down :-(

     > as in k above, so in conk below:  a string is a list of characters:

    >

    >   ['a 'b 'c 'd]

    > "abcd"

    >   first

    > 'a

    >

    > more precisely, "abcdef" is "vector notation" for the list of length

    > six whose first element is the atom 'a, &c.

     Sure, Joy and Haskell do the same.

     >

    > since max and > are atomic operations, they require that their

    > operands

    > are conformable.  that's why

    >

    >     "abcd" 'b >

    > [1 0 0 0]

     That seems an overly restrictive definition of '>'. How are you going to

    sort strings? If the answer is by using a special string comparison

    function (ie. not '>') then my point stands: your code is less generic

    than it could be.

     >

    > (remember - x y > means:  y > x, not x > y).

     Yes, I remember you mentioning that conk works this way some time back,

    but I don't see that this has any relevance to genericity.

     > and

    >

    >     "abcd" 'b max

    > "bbcd"

     This is a different operation than returning the maximum of two values:

    its max applied to a list, ie. [max] cons map.  I would therefore give

    it a different name. The reason is, if you want code to be both generic

    and readable, every name should have _one meaning_.  Overloading the

    same name with different meanings is what gives overloading a bad name

    (no pun intended :-).

    --

    Louis.

## Louis Madon — 2000-07-05 00:38:41

    Louis Madon wrote:

     > stevan apter wrote:

    > > as in k above, so in conk below:  a string is a list of characters:

    > >

    > >   ['a 'b 'c 'd]

    > > "abcd"

    > >   first

    > > 'a

    > >

    > > more precisely, "abcdef" is "vector notation" for the list of length

    > > six whose first element is the atom 'a, &c.

    >

    > Sure, Joy and Haskell do the same.

     Actually, Joy doesn't quite have this, though I believe it should.

    Specifically, in Joy "abcd" first is 'a but ['a 'b 'c 'd] is not "abcd".

    --

    Louis.

## stevan apter — 2000-07-05 04:39:43

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Tuesday, July 04, 2000 8:01 PM

    Subject: Re: [stack] three more proposals about Joy

    > stevan apter wrote:

    > >

    > > ----- Original Message -----

    > > From: Louis Madon <madonl@...>

    > > To: <concatenative@egroups.com>

    > > Sent: Tuesday, July 04, 2000 6:46 PM

    > > Subject: Re: [stack] three more proposals about Joy

    > >

    > > > stevan apter wrote:

    > > > >

    > > > > ----- Original Message -----

    > > > > From: Louis Madon <madonl@...>

    > > > > To: <concatenative@egroups.com>

    > > > > Sent: Tuesday, July 04, 2000 6:12 PM

    > > > > Subject: Re: [stack] three more proposals about Joy

    > > > >

    > > > > > stevan apter wrote:

    > > > > > > > what if I do:

    > > > > > > >

    > > > > > > > ["the" "quick" "brown" "fox"] 0 [min] over

    > > > > > > >

    > > > > > > > will that return "brown" ?

    > > > > > >

    > > > > > > no - the strings differ in length, so you can't compare them.

    > > > > >

    > > > > > Ok, that was my point - you've lost some genericity. So you'll

    > > need

    > > > > > separate functions for 'find_largest_string',

    > > 'find_largest_vector',

    > > > > > etc.

    > > > >

    > > > > but max is an atomic function, so it doesn't make sense to

    > > > > ask for the max of strings of different length.

    > > > >

    > > >

    > > > I really wonder why though. '<' is polymorphic and max can be

    > > trivially

    > > > defined in terms of it:

    > > >

    > > > max == [<] [popd] [pop] ifte

    > > >

    > > >

    > > > In general, it makes sense for max/min to be defined on any type

    > > that

    > > > has a total order.

    > >

    > > i think what we have here is a failure to communictae.  ;-)

    >

    > unfortunately, the link still seems to be down :-(

    >

    >

    > > as in k above, so in conk below:  a string is a list of characters:

    > >

    > >   ['a 'b 'c 'd]

    > > "abcd"

    > >   first

    > > 'a

    > >

    > > more precisely, "abcdef" is "vector notation" for the list of length

    > > six whose first element is the atom 'a, &c.

    >

    > Sure, Joy and Haskell do the same.

    >

    >

    > >

    > > since max and > are atomic operations, they require that their

    > > operands

    > > are conformable.  that's why

    > >

    > >     "abcd" 'b >

    > > [1 0 0 0]

    >

    > That seems an overly restrictive definition of '>'. How are you going to

    > sort strings? If the answer is by using a special string comparison

    > function (ie. not '>') then my point stands: your code is less generic

    > than it could be.

      ["first" "second" "third" "fourth"] up

    [0 3 1 2]

    >

    >

    > >

    > > (remember - x y > means:  y > x, not x > y).

    >

    > Yes, I remember you mentioning that conk works this way some time back,

    > but I don't see that this has any relevance to genericity.

    i mentioned it so that you wouldn't puzzle over the behavior.

    >

    >

    > > and

    > >

    > >     "abcd" 'b max

    > > "bbcd"

    >

    > This is a different operation than returning the maximum of two values:

    > its max applied to a list, ie. [max] cons map.

    no - it's atomic maximumu, which applies to conformable lists.

    I would therefore give

    > it a different name. The reason is, if you want code to be both generic

    > and readable, every name should have _one meaning_.  Overloading the

    > same name with different meanings is what gives overloading a bad name

    > (no pun intended :-).

    >

    >

    > --

    > Louis.

    >

    > ------------------------------------------------------------------------

    > Was the salesman clueless? Productopia has the answers.

    > http://click.egroups.com/1/4633/7/_/_/_/962754978/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## Louis Madon — 2000-07-05 06:50:51

    stevan apter wrote:

     > From: Louis Madon <madonl@...>

    > > stevan apter wrote:

    > > > and

    > > >

    > > >     "abcd" 'b max

    > > > "bbcd"

    > >

    > > This is a different operation than returning the maximum of two values:

    > > its max applied to a list, ie. [max] cons map.

    >

    > no - it's atomic maximumu, which applies to conformable lists.

     We still seem to be on completely different wavelengths ...

    here's my definition of max:

    max : a a -- a

    a binary function that takes two input values of _comparable_ types and

    returns either one or the other, whichever was greater.

    no matter how many types 'max' has implementions for I would expect this

    meaning to be preserved. ie. one name, one meaning.

    your definition of max has at least _two_ meanings. I presume k does not

    support user-defined overloading, then this would be acceptable since

    you can learn all the meanings laid down by the language designers once

    and for all.

     But a language that allows both user-defined overloads _and_ multiple

    meanings per name is bad: to read such code you need to mentally connect

    each name with a particular implementation (ie. disambiguate it) and

    then refer to the implementation code to see what it actually does.

    Moreover, someone could add a new overload at any time that could break

    "tested" code.

     If there is one name, one meaning, then the set of names in a program

    form an unambiguous vocabulary, so for example:

    splitAbove == [>] split

    can be read and understood in isolation without worrying about specific

    types or looking at the implementations of any of the functions used.

    The price you pay (eg. in k) for not having user-defined overloading is

    reduced genericity; it seems you can't write a generic sort or a generic

    find-largest (ie. that can work on integers _and_ strings _and_ dates

    _and_ whatever other types might be added in the future - as long as

    they support > the generic code should not need to be changed).

    --

    Louis.

## stevan apter — 2000-07-05 11:10:48

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Wednesday, July 05, 2000 2:50 AM

    Subject: Re: [stack] three more proposals about Joy

    > stevan apter wrote:

    > > From: Louis Madon <madonl@...>

    > > > stevan apter wrote:

    > > > > and

    > > > >

    > > > >     "abcd" 'b max

    > > > > "bbcd"

    > > >

    > > > This is a different operation than returning the maximum of two values:

    > > > its max applied to a list, ie. [max] cons map.

    > >

    > > no - it's atomic maximumu, which applies to conformable lists.

    >

    > We still seem to be on completely different wavelengths ...

    >

    > here's my definition of max:

    >

    > max : a a -- a

    >

    > a binary function that takes two input values of _comparable_ types and

    > returns either one or the other, whichever was greater.

    right, mine too.  i don't know how you want to explain this, but in k

      "abc" < "defghi"

    length error

    "abc" < "defghi"

          ^

    do you want to say that two strings are not comparable, or not simply or

    atomically comparable, or not "types"?  or do you want to say that they

    (as we do) that they are not conformable?  but note that:

      "abc" <\:/: "defghi"  / less-than-eachleft-eachright

    (1 1 1

     1 1 1

     1 1 1

     1 1 1

     1 1 1

     1 1 1)

    atomic functions encapsulate this geneeral "drill-down" behavior for

    an infinite range of conformable structures.

    on the other other hand, the two (atomic) symbols are:

        `abc < `defghi

    1

    <, >, =, | (max), & (min) etc. are atomic functions.  strings

    are not atomic types.  symbols are.

    >

    >

    > no matter how many types 'max' has implementions for I would expect this

    > meaning to be preserved. ie. one name, one meaning.

    agreed.

    >

    > your definition of max has at least _two_ meanings.

    it does?  i don't think so.  like any other atomic dyadic function, max

    takes two conformable arguments and applies at the atoms.

    > I presume k does not

    > support user-defined overloading, then this would be acceptable since

    > you can learn all the meanings laid down by the language designers once

    > and for all.

    right.

    >

    >  But a language that allows both user-defined overloads _and_ multiple

    > meanings per name is bad: to read such code you need to mentally connect

    > each name with a particular implementation (ie. disambiguate it) and

    > then refer to the implementation code to see what it actually does.

    > Moreover, someone could add a new overload at any time that could break

    > "tested" code.

    i guess so.  but as you say, we don't have user-defined types.

    >

    >  If there is one name, one meaning, then the set of names in a program

    > form an unambiguous vocabulary, so for example:

    >

    > splitAbove == [>] split

    >

    > can be read and understood in isolation without worrying about specific

    > types or looking at the implementations of any of the functions used.

    >

    > The price you pay (eg. in k) for not having user-defined overloading is

    > reduced genericity; it seems you can't write a generic sort or a generic

    > find-largest (ie. that can work on integers _and_ strings _and_ dates

    > _and_ whatever other types might be added in the future - as long as

    > they support > the generic code should not need to be changed).

    well, that's true.  we've often wondered what the tradeoffs would be

    if we provided the ability to introduce new types.  e.g. currently we

    represent dates as integers - say, 19990302.  so we can't overload

    + and - to do date arithmetic.  we have to write functions dateadd and

    datesub.  the fact that integer n in a program is a date is a fact

    about the programmer's intentions, the type exists only in the programmer's

    mind.  the added value of having the interpreter know that n is a date

    seems small, less than it might be in scalar languages.  in all, an

    open question.

    >

    >

    > --

    > Louis.

    >

    > ------------------------------------------------------------------------

    > CLICK HERE AND START SAVING ON LONG DISTANCE BILLS TODAY!

    > http://click.egroups.com/1/4125/7/_/_/_/962779556/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## Louis Madon — 2000-07-05 13:50:58

    stevan apter wrote:

     >

    > ----- Original Message -----

    > From: Louis Madon <madonl@...>

    > To: <concatenative@egroups.com>

    > Sent: Wednesday, July 05, 2000 2:50 AM

    > Subject: Re: [stack] three more proposals about Joy

    >

    > > stevan apter wrote:

    > > > From: Louis Madon <madonl@...>

    > > > > stevan apter wrote:

    > > > > > and

    > > > > >

    > > > > >     "abcd" 'b max

    > > > > > "bbcd"

    > > > >

    > > > > This is a different operation than returning the maximum of two values:

    > > > > its max applied to a list, ie. [max] cons map.

    > > >

    > > > no - it's atomic maximumu, which applies to conformable lists.

    > >

    > > We still seem to be on completely different wavelengths ...

    > >

    > > here's my definition of max:

    > >

    > > max : a a -- a

    > >

    > > a binary function that takes two input values of _comparable_ types and

    > > returns either one or the other, whichever was greater.

    >

    > right, mine too.  i don't know how you want to explain this, but in k

    >

    >   "abc" < "defghi"

    > length error

    > "abc" < "defghi"

    >       ^

     Right, because as you say "atomic functions apply at the atoms" and so a

    binary function needs an equal supply of atoms from each list argument.

     > do you want to say that two strings are not comparable, or not simply or

    > atomically comparable, or not "types"?  or do you want to say that they

    > (as we do) that they are not conformable?

    > but note that:

    >

    >   "abc" <\:/: "defghi"  / less-than-eachleft-eachright

    > (1 1 1

    > 1 1 1

    > 1 1 1

    > 1 1 1

    > 1 1 1

    > 1 1 1)

    >

    > atomic functions encapsulate this geneeral "drill-down" behavior for

    > an infinite range of conformable structures.

    >

    > on the other other hand, the two (atomic) symbols are:

    >

    >     `abc < `defghi

    > 1

    >

    > <, >, =, | (max), & (min) etc. are atomic functions.  strings

    > are not atomic types.  symbols are.

     Ok, all this makes sense. Now the way I would define the meaning of

    'max' then is something like:

    max : x y -- r

      if x and y are atomic then return greater of x, y

       else if x is a list and y is atomic then recursively apply (max y) to

    elements of x

       else ... etc for remaining x/y combos

     > >

    > > no matter how many types 'max' has implementions for I would expect

    > this

    > > meaning to be preserved. ie. one name, one meaning.

    >

    > agreed.

    >

    > >

    > > your definition of max has at least _two_ meanings.

    >

    > it does?  i don't think so.  like any other atomic dyadic function,

    > max takes two conformable arguments and applies at the atoms.

     It does, but I need to clarify what I mean by "two".  Whenever the

    meaning assigned to a name involves type distinctions, I consider it to

    have multiple meanings. For 'max' the behaviour clearly varies depending

    on whether both arguments are atomic or not.  To see why this is

    significant, consider this example:

    top-larger == dup [max] dip =

    this function expects two comparable values on the stack and returns

    True if the top-of-stack value is larger.  In conk this code can only be

    guaranteed to work for atomic values. It breaks otherwise, because the

    behaviour of max changes in the presence of list arguments such that you

    can no longer assume equality between one of the inputs and the result.

    Code that works fine initially but then fails (basically does something

    unexpected) when new types come along is a symptom of having multiple

    meanings - the new meanings are inconsistent with prior understanding.

    Now in k, as I've said, this isn't really an issue, since the user can't

    introduce new types nor modify the meanings of existing types nor add

    any new overloads.

    But in a language that does support type definition and overloading, the

    code can easily become very confusing and fragile if the "one name, one

    meaning" principle isn't followed. Basically,  any properties required

    by some generic code for one specific type must also apply to _all_

    other types that may be given to that code.  This in turn makes it

    possible to read the code without even thinking about specific types

    (you just interpret the names - they each have one meaning so there is

    no ambiguity).

     >

    > > I presume k does not support user-defined overloading, then this would be acceptable

    > since you can learn all the meanings laid down by the language designers

    > once and for all.

    >

    > right.

    >

    > >

    > >  But a language that allows both user-defined overloads _and_ multiple

    > > meanings per name is bad: to read such code you need to mentally connect

    > > each name with a particular implementation (ie. disambiguate it) and

    > > then refer to the implementation code to see what it actually does.

    > > Moreover, someone could add a new overload at any time that could break

    > > "tested" code.

    >

    > i guess so.  but as you say, we don't have user-defined types.

    >

    > >

    > >  If there is one name, one meaning, then the set of names in a program

    > > form an unambiguous vocabulary, so for example:

    > >

    > > splitAbove == [>] split

    > >

    > > can be read and understood in isolation without worrying about

    > specific

    > > types or looking at the implementations of any of the functions

    > used.

    > >

    > > The price you pay (eg. in k) for not having user-defined overloading

    > is

    > > reduced genericity; it seems you can't write a generic sort or a

    > generic

    > > find-largest (ie. that can work on integers _and_ strings _and_

    > dates

    > > _and_ whatever other types might be added in the future - as long as

    > > they support > the generic code should not need to be changed).

    >

    > well, that's true.  we've often wondered what the tradeoffs would be

    > if we provided the ability to introduce new types.  e.g. currently we

    > represent dates as integers - say, 19990302.  so we can't overload

    > + and - to do date arithmetic.  we have to write functions dateadd and

    > datesub.  the fact that integer n in a program is a date is a fact

    > about the programmer's intentions, the type exists only in the

    > programmer's

    > mind.  the added value of having the interpreter know that n is a date

    > seems small, less than it might be in scalar languages.  in all, an

    > open question.

     Yes, thats a reasonable position. I'm interested in highly generic code

    for benefits of conciseness, re-usability and quick modifiability (which

    ultimately could mean much higher productivity). Its what I'm working on

    in my version of Joy and time will tell what merit my approach really

    has.

    --

    Louis.

## sa@dfa.com — 2000-07-05 14:18:24

    stevan apter wrote:

     >

    > ----- Original Message -----

    > From: Louis Madon <madonl@...>

    > To: <concatenative@egroups.com>

    > Sent: Wednesday, July 05, 2000 2:50 AM

    > Subject: Re: [stack] three more proposals about Joy

    >

    > > stevan apter wrote:

    > > > From: Louis Madon <madonl@...>

    > > > > stevan apter wrote:

    > > > > > and

    > > > > >

    > > > > >     "abcd" 'b max

    > > > > > "bbcd"

    > > > >

    > > > > This is a different operation than returning the maximum of two

     values:

     > > > > its max applied to a list, ie. [max] cons map.

    > > >

    > > > no - it's atomic maximumu, which applies to conformable lists.

    > >

    > > We still seem to be on completely different wavelengths ...

    > >

    > > here's my definition of max:

    > >

    > > max : a a -- a

    > >

    > > a binary function that takes two input values of _comparable_ types and

    > > returns either one or the other, whichever was greater.

    >

    > right, mine too.  i don't know how you want to explain this, but in k

    >

    >   "abc" < "defghi"

    > length error

    > "abc" < "defghi"

    >       ^

     Right, because as you say "atomic functions apply at the atoms" and so a

    binary function needs an equal supply of atoms from each list argument.

         that's right if you think of f(atom,list) as first replicating

         the atom count-list-many times (and doing so recursively).  but

         remember that e.g. a list of three atoms and a list of three lists

         of any structure are conformable.  &c.  so e.g. a 5 x 4 x 6 x 3

         list can be added to a 5 x 4 list, yielding a 5 x 4 x 6 x 3 list.

     > do you want to say that two strings are not comparable, or not simply or

    > atomically comparable, or not "types"?  or do you want to say that they

    > (as we do) that they are not conformable?

    > but note that:

    >

    >   "abc" <\:/: "defghi"  / less-than-eachleft-eachright

    > (1 1 1

    > 1 1 1

    > 1 1 1

    > 1 1 1

    > 1 1 1

    > 1 1 1)

    >

    > atomic functions encapsulate this geneeral "drill-down" behavior for

    > an infinite range of conformable structures.

    >

    > on the other other hand, the two (atomic) symbols are:

    >

    >     `abc < `defghi

    > 1

    >

    > <, >, =, | (max), & (min) etc. are atomic functions.  strings

    > are not atomic types.  symbols are.

     Ok, all this makes sense. Now the way I would define the meaning of

    'max' then is something like:

    max : x y -- r

      if x and y are atomic then return greater of x, y

       else if x is a list and y is atomic then recursively apply (max y) to

    elements of x

       else ... etc for remaining x/y combos

    ok - we just say "max is atomic", since the atomic penetration algorithm

    (elsewhere called "scalar extension") is the same for all of them.

     > >

    > > no matter how many types 'max' has implementions for I would expect

    > this

    > > meaning to be preserved. ie. one name, one meaning.

    >

    > agreed.

    >

    > >

    > > your definition of max has at least _two_ meanings.

    >

    > it does?  i don't think so.  like any other atomic dyadic function,

    > max takes two conformable arguments and applies at the atoms.

     It does, but I need to clarify what I mean by "two".  Whenever the

    meaning assigned to a name involves type distinctions, I consider it to

    have multiple meanings. For 'max' the behaviour clearly varies depending

    on whether both arguments are atomic or not.  To see why this is

    significant, consider this example:

    top-larger == dup [max] dip =

    this function expects two comparable values on the stack and returns

    True if the top-of-stack value is larger.  In conk this code can only be

    guaranteed to work for atomic values. It breaks otherwise, because the

    behaviour of max changes in the presence of list arguments such that you

    can no longer assume equality between one of the inputs and the result.

         it breaks whenever the arguments are not conformable.

         in conk, top_larger will return a boolean result determined

         by the shapes of its arguments:

           5 10 draw

         [3 0 4 3 1 4 4 3 3 1]

           5 10 draw

         [3 0 4 3 1 4 4 3 3 1] [1 2 2 4 4 3 0 3 4 1]

           dup [max] dip =

          [0 1 0 1 1 0 0 1 1 1]

    Code that works fine initially but then fails (basically does something

    unexpected) when new types come along is a symptom of having multiple

    meanings - the new meanings are inconsistent with prior understanding.

    Now in k, as I've said, this isn't really an issue, since the user can't

    introduce new types nor modify the meanings of existing types nor add

    any new overloads.

         however, if we had such a facility, then the new types would

         be atomic.  so atomic extension would apply.

    But in a language that does support type definition and overloading, the

    code can easily become very confusing and fragile if the "one name, one

    meaning" principle isn't followed. Basically,  any properties required

    by some generic code for one specific type must also apply to _all_

    other types that may be given to that code.  This in turn makes it

    possible to read the code without even thinking about specific types

    (you just interpret the names - they each have one meaning so there is

    no ambiguity).

         ok

     >

    > > I presume k does not support user-defined overloading, then this would

     be acceptable

     > since you can learn all the meanings laid down by the language designers

    > once and for all.

    >

    > right.

    >

    > >

    > >  But a language that allows both user-defined overloads _and_ multiple

    > > meanings per name is bad: to read such code you need to mentally

     connect

     > > each name with a particular implementation (ie. disambiguate it) and

    > > then refer to the implementation code to see what it actually does.

    > > Moreover, someone could add a new overload at any time that could break

    > > "tested" code.

    >

    > i guess so.  but as you say, we don't have user-defined types.

    >

    > >

    > >  If there is one name, one meaning, then the set of names in a program

    > > form an unambiguous vocabulary, so for example:

    > >

    > > splitAbove == [>] split

    > >

    > > can be read and understood in isolation without worrying about

    > specific

    > > types or looking at the implementations of any of the functions

    > used.

    > >

    > > The price you pay (eg. in k) for not having user-defined overloading

    > is

    > > reduced genericity; it seems you can't write a generic sort or a

    > generic

    > > find-largest (ie. that can work on integers _and_ strings _and_

    > dates

    > > _and_ whatever other types might be added in the future - as long as

    > > they support > the generic code should not need to be changed).

    >

    > well, that's true.  we've often wondered what the tradeoffs would be

    > if we provided the ability to introduce new types.  e.g. currently we

    > represent dates as integers - say, 19990302.  so we can't overload

    > + and - to do date arithmetic.  we have to write functions dateadd and

    > datesub.  the fact that integer n in a program is a date is a fact

    > about the programmer's intentions, the type exists only in the

    > programmer's

    > mind.  the added value of having the interpreter know that n is a date

    > seems small, less than it might be in scalar languages.  in all, an

    > open question.

     Yes, thats a reasonable position. I'm interested in highly generic code

    for benefits of conciseness, re-usability and quick modifiability (which

    ultimately could mean much higher productivity). Its what I'm working on

    in my version of Joy and time will tell what merit my approach really

    has.

         naturally, i am eager to see how this shakes out.

    --

    Louis.

    ------------------------------------------------------------------------

    Free, Unlimited Calls Anywhere!

    Conference in the whole family on the same call.

    Let the fights begin!  Visit Firetalk.com - Click below.

    http://click.egroups.com/1/5476/7/_/_/_/962804739/

    ------------------------------------------------------------------------

    To unsubscribe from this group, send an email to:

    concatenative-unsubscribe@egroups.com

## Louis Madon — 2000-07-05 22:43:43

    sa@... wrote:

     > top-larger == dup [max] dip =

    >

    > this function expects two comparable values on the stack and returns

    > True if the top-of-stack value is larger.  In conk this code can only be

    > guaranteed to work for atomic values. It breaks otherwise, because the

    > behaviour of max changes in the presence of list arguments such that you

    > can no longer assume equality between one of the inputs and the

    > result.

    >

    >      it breaks whenever the arguments are not conformable.

    >      in conk, top_larger will return a boolean result determined

    >      by the shapes of its arguments:

    >

    >        5 10 draw

    >      [3 0 4 3 1 4 4 3 3 1]

    >        5 10 draw

    >      [3 0 4 3 1 4 4 3 3 1] [1 2 2 4 4 3 0 3 4 1]

    >        dup [max] dip =

    >       [0 1 0 1 1 0 0 1 1 1]

     Ok, so what does this do:

    top-larger "its larger" "its smaller" branch

    When the values are both atomic it works fine, but in the presence of

    list arguments - even if they're conforming - it breaks, correct?

    --

    Louis.

## Louis Madon — 2000-07-05 23:21:23

    Louis Madon wrote:

     >

    > sa@... wrote:

    >

    > > top-larger == dup [max] dip =

    > >

    > > this function expects two comparable values on the stack and returns

    > > True if the top-of-stack value is larger.  In conk this code can

    > only be

    > > guaranteed to work for atomic values. It breaks otherwise, because

    > the

    > > behaviour of max changes in the presence of list arguments such that

    > you

    > > can no longer assume equality between one of the inputs and the

    > > result.

    > >

    > >      it breaks whenever the arguments are not conformable.

    > >      in conk, top_larger will return a boolean result determined

    > >      by the shapes of its arguments:

    > >

    > >        5 10 draw

    > >      [3 0 4 3 1 4 4 3 3 1]

    > >        5 10 draw

    > >      [3 0 4 3 1 4 4 3 3 1] [1 2 2 4 4 3 0 3 4 1]

    > >        dup [max] dip =

    > >       [0 1 0 1 1 0 0 1 1 1]

    >

    > Ok, so what does this do:

    >

    > top-larger "its larger" "its smaller" branch

    >

    > When the values are both atomic it works fine, but in the presence of

    > list arguments - even if they're conforming - it breaks, correct?

     Then again, on reflection, I think it would return (eg.)

    ["its smaller" "its smaller" "its larger" ... etc]

    So perhaps it is possible to view the behaviour as having a single

    meaning (independant of specific types), though a bit different to what

    I'm used to.

    It is interesting.

    --

    Louis.

## stevan apter — 2000-07-06 01:22:39

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Wednesday, July 05, 2000 6:43 PM

    Subject: Re: [stack] three more proposals about Joy

    > Ok, so what does this do:

    >

    > top-larger "its larger" "its smaller" branch

    >

    > When the values are both atomic it works fine, but in the presence of

    > list arguments - even if they're conforming - it breaks, correct?

    assuming branch requires an atom, yes.

    >

    >

    > --

    > Louis.

    >

    > ------------------------------------------------------------------------

    > Who invented Gatorade -- and what part did it play in

    > winning the1967 Orange Bowl? Find out the true facts at

    > http://click.egroups.com/1/6212/7/_/_/_/962836699/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## stevan apter — 2000-07-06 01:40:47

    ----- Original Message -----

    From: Louis Madon <madonl@...>

    To: <concatenative@egroups.com>

    Sent: Wednesday, July 05, 2000 7:21 PM

    Subject: Re: [stack] three more proposals about Joy

    > >

    > > Ok, so what does this do:

    > >

    > > top-larger "its larger" "its smaller" branch

    > >

    > > When the values are both atomic it works fine, but in the presence of

    > > list arguments - even if they're conforming - it breaks, correct?

    >

    > Then again, on reflection, I think it would return (eg.)

    >

    > ["its smaller" "its smaller" "its larger" ... etc]

    oh, *that* branch.  ;-)

    well, here's what conk does:

        [1 0 1 0 1] "true" "false" branch

    "true" "false" "true" "false" "true"

    and here's how it's implemented:

        branch:{(3_ x)E/x x 2}

    the key is x (the stack) indexed by x 2 (the boolean, of whatever

    shape or complexity).  so yes, even if the boolean is some deeply

    structured list, the result will inherit that structure. minus its

    outer frame:

          [[1 0 1 0][0 1 0]] "true "false" branch

    ["true" "false" "true" "false"] ["false" "true" "false"]

          [1 0 1] enlist [2 3] take

    [[[1 0 1] [1 0 1] [1 0 1]] [[1 0 1] [1 0 1] [1 0 1]]]

          "true" "false" branch

    [["true" "false" "true"] ["true" "false" "true"] ["true" "false" "true"]] [["tr

    e" "false" "true"] ["true" "false" "true"] ["true" "false" "true"]]

    >

    >

    > So perhaps it is possible to view the behaviour as having a single

    > meaning (independant of specific types), though a bit different to what

    > I'm used to.

    >

    > It is interesting.

    >

    >

    > --

    > Louis.

    >

    > ------------------------------------------------------------------------

    > Who invented Gatorade -- and what part did it play in

    > winning the1967 Orange Bowl? Find out the true facts at

    > http://click.egroups.com/1/6212/7/_/_/_/962839412/

    > ------------------------------------------------------------------------

    >

    > To unsubscribe from this group, send an email to:

    > concatenative-unsubscribe@egroups.com

    >

    >

    >

    >

## wtanksley@bigfoot.com — 2000-08-01 18:34:47

    From: iepos@... [mailto:iepos@...]

     >Hello folks ...

    >The last while, I've been thinking a bit about a few ways I would like

    >Joy to be modified. You may or may not like these ideas ...

    >1) Design the system so that the user feels free to pile tons of items

    >   onto the stack (treating it as an array). Modify the "size"

    >   primitive

    >   to tell how many items are on the stack. Add a primitive "wrap"

    >   that wraps the whole stack up into a list.

     This type of operation does have its uses, but its biggest shortcoming is

    that it demands absolute knowledge of the stack.  It essentially treats the

    stack as a global variable.  This is just fine if you're expecting that (so

    there's no problem with including words which have those actions), but it's

    wrong to build the language around such a dangerous premise.

     >2) Eliminate the ability to do direct introspection on quotations.

    >   This is actually a consequence of the suggestion in #1;

    >   "first", "rest", "at", "take", "size" could no longer be used to

    >   peek into a quotation, since the reformed versions fiddle with items

    >   directly on the stack instead of in quotations.

     My solution for this is to eliminate the ability to directly execute a

    quotation; instead, you can execute only functions.  Fortunately, functions

    may be compiled from quotations.  (And, of course, we can define a word

    which compiles a quotation anonymously and executes the resulting function

    pointer.)

     >3) Replace Joy's "==" construct, and its friends, "LIBRA",

    >   "HIDE", "IN",

    >   and "END" with a fully-fledged lambda construct. (Okay, I've already

    >   mentioned this before).

     Very bad idea, especially since your definition of "fully-fledged" also

    requires special cases for quotation (for example, [x] would push x on the

    stack, instead of pushing [x] on the stack, unless x is multiple elements).

    Also, lambda by itself cannot handle exports; a lambda name endures only as

    long as its scope does.

    It would certainly be possible to define a pair of definition constructs,

    though:

    [5 4 +] lambda: x

    5 4 + constant: y

    x --> 9

    y --> 9

    These definitions could be valid until the end of the scope in which they

    were defined.  Of course, you'd lose some of the nice properties of Joy's

    current naming system, in that naming errors wouldn't be known until

    runtime.

    An interesting problem: I don't see any way to handle quotation here.  If

    you quote x or y, it seems that you've just quoted something which may be

    transient.  Quoting x is particularly hard; here's what it might look like:

     [x] --> [9]

    or

     [x] --> [5 4 +]

    The problem is clear: the lambda reference has to execute even in the middle

    of a quotation.  Now, this is a handy ability, so rather than choosing one

    possible operation I'm going to choose both.

    "5 4 +" text-macro: z

    [5 4 +] macro: w

    [5 4 +] lambda: x

    All of these look the same when used unquoted.  When quoted, though:

    [x] --> [[5 4 +] i]

    [z] --> [5 4 +]

    [w] --> [9]

    'macro:' can be used to define all of the others, because it simply

    specifies execution at compile-time.  However, we would require a way to

    distinguish execution within a quotation from execution outside of a

    quotation in order to do that correctly.

    I'm not going to continue; this has far surpassed my tolerance for language

    cruft.

     >- "iepos" (Brent Kerby)

     -Billy

## iepos@tunes.org — 2000-08-03 18:07:11

## iepos@tunes.org — 2000-08-04 14:52:02

    Sorry about the blank message yesterday ...

    not sure quite how that happened.

     > >1) Design the system so that the user feels free to pile tons of items

    > >   onto the stack (treating it as an array). Modify the "size"

    > >   primitive

    > >   to tell how many items are on the stack. Add a primitive "wrap"

    > >   that wraps the whole stack up into a list.

    >

    > This type of operation does have its uses, but its biggest shortcoming is

    > that it demands absolute knowledge of the stack.  It essentially treats the

    > stack as a global variable.  This is just fine if you're expecting that (so

    > there's no problem with including words which have those actions), but it's

    > wrong to build the language around such a dangerous premise.

     Yes. there are some disadvantages to this style. It might not be fit

    in some systems. I still like the idea, though.

     > >2) Eliminate the ability to do direct introspection on quotations.

    > >   This is actually a consequence of the suggestion in #1;

    > >   "first", "rest", "at", "take", "size" could no longer be used to

    > >   peek into a quotation, since the reformed versions fiddle with items

    > >   directly on the stack instead of in quotations.

    >

    > My solution for this is to eliminate the ability to directly execute a

    > quotation; instead, you can execute only functions.  Fortunately, functions

    > may be compiled from quotations.  (And, of course, we can define a word

    > which compiles a quotation anonymously and executes the resulting function

    > pointer.)

     Hmm. Let me get this straight... By "quotation", you mean a list of

    execution tokens, a high-level representation of a program. By "function",

    you mean a list of native instruction bytes. Is that right?

     > It would certainly be possible to define a pair of definition constructs,

    > though:

    >

    > [5 4 +] lambda: x

    > 5 4 + constant: y

    >

    > x --> 9

    > y --> 9

     Yes, I believe it would be useful to have both "lambda:" and "constant:",

    as you suggest. However, it is possible to construct "constant:" as

    "unitlist lambda:". "unitlist" takes an item off the stack and converts

    it into a _program that pushes that item_, so that it is a valid input

    to "lambda:" (which only accepts programs, and nothing else).

     > The problem is clear: the lambda reference has to execute even in the middle

    > of a quotation.  Now, this is a handy ability, so rather than choosing one

    > possible operation I'm going to choose both.

    >

    > "5 4 +" text-macro: z

    > [5 4 +] macro: w

    > [5 4 +] lambda: x

    >

    > All of these look the same when used unquoted.  When quoted, though:

    > [...]

     Lambdas are confusing, and there are many ways of doing them, as you say.

    I'm not sure exactly what the best way is ...

     > -Billy

     - "iepos" (Brent Kerby)

## wtanksley@bigfoot.com — 2000-08-04 23:08:42

    From: iepos@... [mailto:iepos@...]

    [treating the entire stack as an object]

     >> This type of operation does have its uses, but its biggest

    >> shortcoming is

    >> that it demands absolute knowledge of the stack.  It

    >> essentially treats the

    >> stack as a global variable.  This is just fine if you're

    >> expecting that (so

    >> there's no problem with including words which have those

    >> actions), but it's

    >> wrong to build the language around such a dangerous premise.

    >Yes. there are some disadvantages to this style. It might not be fit

    >in some systems. I still like the idea, though.

     I don't, but I do like some ideas which are related to it.  For example, I

    believe an explicitly finite stack can be useful.  Chuck Moore's programs

    use a 18-deep stack without problems.

    When it comes right down to it, there's no such thing as an infinitely deep

    stack; so it's better to have a small stack whose size you know exactly than

    to have a huge stack which you mistakenly pretend is infinite.

     >> >2) Eliminate the ability to do direct introspection on quotations.

    >> >   This is actually a consequence of the suggestion in #1;

    >> >   "first", "rest", "at", "take", "size" could no longer be used to

    >> >   peek into a quotation, since the reformed versions

    >> >   fiddle with items

    >> >   directly on the stack instead of in quotations.

    >> My solution for this is to eliminate the ability to directly

    >> execute a

    >> quotation; instead, you can execute only functions.

    >> Fortunately, functions

    >> may be compiled from quotations.  (And, of course, we can

    >> define a word which compiles a quotation anonymously and

    >> executes the resulting function pointer.)

    >Hmm. Let me get this straight... By "quotation", you mean a list of

    >execution tokens, a high-level representation of a program.

     Yes.

     >By "function",

    >you mean a list of native instruction bytes. Is that right?

     Um...  Not really.  A function has no structure, so it's not a "list" of

    native instruction bytes.  Now, it might be implemented that way; but I

    offer no guarantees.

     >> The problem is clear: the lambda reference has to execute

    >> even in the middle

    >> of a quotation.  Now, this is a handy ability, so rather

    >> than choosing one possible operation I'm going to choose

    >> both.

    >> "5 4 +" text-macro: z

    >> [5 4 +] macro: w

    >> [5 4 +] lambda: x

    >> All of these look the same when used unquoted.  When quoted, though:

    >> [...]

    >Lambdas are confusing, and there are many ways of doing them,

    >as you say. I'm not sure exactly what the best way is ...

     IMO, the best thing to do is to avoid them like the plague that they are.

    They're TOTALLY unneeded, and completely change the rules of the language in

    a way which doesn't make sense.

    Both text macros and macros are useful, though.

    Of course, I'm opinionated.  :-)  I also don't really like Joy's quotation

    literals; they help introduce many of the ambiguities encountered by

    lambdas.  They also change Joy's perfect list structure into a tree

    structure, which has resulted in many people confusing Joy with Scheme.

     >- "iepos" (Brent Kerby)

     -Billy