# Re: [stack] Re: Fw: ANNOUNCE: enhancements to JOY

## John Cowan — 2001-06-26 19:13:53

    Jack Waugh wrote:

     > The announcement in comp.lang.functional (archived, by the way, at

    > http://groups.google.com/groups?

    > q=Joy&hl=en&group=comp.lang.functional&safe=off&rnum=1&ic=1&selm=9g9sp

    > u%247c0%241%40latcs1.cs.latrobe.EDU.AU if you can get all that into

    > your browser) promises "Files as a datatype, together with some

    > common functions for manipulating files and doing I/O."  Are the

    > files now gone from function arguments and results (other than any

    > files that might happen to occupy positions in the stack)?

     I have no clue what this means.

    --

    There is / one art             || John Cowan <jcowan@...>

    no more / no less              || http://www.reutershealth.com

    to do / all things             || http://www.ccil.org/~cowan

    with art- / lessness           \\ -- Piet Hein

## Manfred von Thun — 2001-06-27 02:34:09

    I thought that by now I would have sorted out most bugs in

    at least the core parts of Joy. But here is one that has me

    stumped  -  it occurs in both Joy0 and Joy1:

    true  not.

    false                        OK

    true  dup and.

    true                         OK

    [5]  [dup *] map.

    [25]                         OK

    [true]  [not] map.

      run time error: different type needed for not

    [true]  [dup and] map

      run time error: different type needed for and

    Same strange message for "false" instead of "true",

    and for "or" instead of "and". Same message for

    longer lists of logical values. But empty list is OK:

    []  [not] map

    []                           OK

    []  [dup and] map

    []                           OK

    I'm stumped. I am still busy finalising marks for the

    semester, so I won't be able to attend to this bug for

    a while.  In the meantime ... (:-)

      - Manfred

## Louis Madon — 2001-06-27 09:00:38

    I had a quick look and it seems the problem is that the list contains

    instances of the _function_ 'true' rather than its value. ie. the same

    kind of thing that you get when you do '[cons] first' for example.  If

    you create a little helper function like this:

    bare_i == [] cons i

    then you can do:

    [true] [bare_i not] map

    [false]                                                  OK

    this also explains why doing 'true not' is ok. 'true' gets executed

    first - leaving a boolean on the stack - and only then does 'not'

    execute.

    I don't know the C code that well, but I think that to get the same

    semantics as for other literals (numbers, strings, etc) it is neccesary

    for true and false to also be handled specially when read.  For other

    functions (cons, pop, etc) getting a bare function is what you want so

    the existing semantics should not be changed for them.

    I hope this helps,

    Louis.

     On Wednesday, June 27, 2001, at 12:34  PM, Manfred von Thun wrote:

    > I thought that by now I would have sorted out most bugs in

    > at least the core parts of Joy. But here is one that has me

    > stumped  -  it occurs in both Joy0 and Joy1:

    >

    > true  not.

    > false                        OK

    > true  dup and.

    > true                         OK

    > [5]  [dup *] map.

    > [25]                         OK

    >

    > [true]  [not] map.

    >   run time error: different type needed for not

    > [true]  [dup and] map

    >   run time error: different type needed for and

    >

    > Same strange message for "false" instead of "true",

    > and for "or" instead of "and". Same message for

    > longer lists of logical values. But empty list is OK:

    >

    > []  [not] map

    > []                           OK

    > []  [dup and] map

    > []                           OK

    >

    > I'm stumped. I am still busy finalising marks for the

    > semester, so I won't be able to attend to this bug for

    > a while.  In the meantime ... (:-)

    >   - Manfred

    [Non-text portions of this message have been removed]

## John Cowan — 2001-06-29 22:01:58

    Louis Madon wrote:

     > I had a quick look and it seems the problem is that the list contains

    > instances of the _function_ 'true' rather than its value.

     Absolutely right.  This is a very fundamental issue in Joy:

    even if DEFINE five == 5, the lists [five five five] and [5 5 5]

    are very different things.  The list [true true true] is like

    the former; there is no boolean equivalent of the latter.

    Manfred, I think we need to regularize the policy here, but

    I'm not sure what the Right Thing might be.

    --

    There is / one art             || John Cowan <jcowan@...>

    no more / no less              || http://www.reutershealth.com

    to do / all things             || http://www.ccil.org/~cowan

    with art- / lessness           \\ -- Piet Hein

## Manfred von Thun — 2001-07-02 01:49:20

    On Wed, 27 Jun 2001, Louis Madon wrote:

     > I had a quick look and it seems the problem is that the list contains

    > instances of the _function_ 'true' rather than its value. ie. the same

    > kind of thing that you get when you do '[cons] first' for example.  If

    > you create a little helper function like this:

    >

    > bare_i == [] cons i

    >

    >

    > then you can do:

    >

    > [true] [bare_i not] map

    > [false]                                                  OK

    >

    >

    > this also explains why doing 'true not' is ok. 'true' gets executed

    > first - leaving a boolean on the stack - and only then does 'not'

    > execute.

    >

    >

    > I don't know the C code that well, but I think that to get the same

    > semantics as for other literals (numbers, strings, etc) it is neccesary

    > for true and false to also be handled specially when read.  For other

    > functions (cons, pop, etc) getting a bare function is what you want so

    > the existing semantics should not be changed for them.

    >

    > I hope this helps,

    > Louis.

     Thank you very much, Louis, your analysis is exactly right.

    I am most embarassed about writing wrong code like that,

    not noticing the mistake earlier, and not seeing where the

    problem lies. I thought it was specific to map, but actually

    it also arises for filter, split and fold, and maybe others.

    Here is a temporary quick fix:

    1. in file scan.c   (towards the very end)

         in function getsym()

           in the default clause

             just after the two lines

               if (strcmp,id,"==") == 0)

                 { sym = EQDEF; return; }

             insert the four lines

               if (strcmp(id,"true") == 0)

                 { sym = BOOLEAN_; num = 1; return; }

               if (strcmp(id,"false") == 0)

                 { sym = BOOLEAN_; num = 0; return; }

    2. in file utils.c

         in function readfactor()

           to the line

             case INTEGER_: case CHAR_: case STRING_:

           prefix another case -

             case BOOLEAN_:

    3. The two changes above are adequate, but if this solution is

       made permanent then hygene demands additionally

       a) delete the two "true" and "false" calls to the PUSH(..) macro

       b) change the optable entry so that true_ and false_ cannot be called

          at all; use dummy_ instead.

    BUT - although this is OK as a fix, I am not so sure I like it:

    1. Similar fixes are needed for the half dozen other calls to

       the PUSH(..) macro, for maxint, setsize etc

       If all those calls are deleted, the whole macro should go.

    2. It is inelegant and unsafe. Ideally the strings "true" and "false"

       (and the half dozen others) should occur only once in the entire

       implementation. (Imagine changing to German Joy ("Freude"?):

       "wahr" and "falsch" now have to be used in several places.)

       It is also slightly inefficient to have that long chain of

       special case if-then's in the C-code for scan.c before the

       most common default clause is reached.

    3. A better solution would be to have a single mechanism for all

       for all these case, possibly somewhere inside file utils.c

       function readfactor. Of course the information as to what is

       and is not a special case will have to be found somewhere.

       My current thinking is that perhaps that sort of thing should

       be in file interp.c, declaration of optable, by having additional

       fields. Currently there is a string field for the spelling,

       used for reading and writing, a function field for executing,

       and two further string fields for help. Additional fields

       could be useful for all sorts of things - like arities for

       operators and combinators.

       But I am still thinking about all this.

    Again, thank you Louis,

      - Manfred

## Manfred von Thun — 2001-07-02 02:29:54

    On Fri, 29 Jun 2001, John Cowan wrote:

     > Louis Madon wrote:

    >

    > > I had a quick look and it seems the problem is that the list contains

    > > instances of the _function_ 'true' rather than its value.

    >

    >

    > Absolutely right.  This is a very fundamental issue in Joy:

    > even if DEFINE five == 5, the lists [five five five] and [5 5 5]

    > are very different things.  The list [true true true] is like

    > the former; there is no boolean equivalent of the latter.

    >

    > Manfred, I think we need to regularize the policy here, but

    > I'm not sure what the Right Thing might be.

     I'm not at all sure myself. You will have seen my quick fix

    to the problem and my doubts about it in my reply to Louis.

    Until you and others have looked at it I won't change the

    C-code on the web page, and I suggest you don't incorparate

    these changes into the joy.tar.gz file yet.

    I've only had one more thought on it all, consider this:

    DEFINE

        five == 5;

        fourth == pop pop pop;

        third == pop pop;

        bare_i == [] cons i.

    bare_i is what Louis called it. I have sometimes thought that perhaps

    there should be a primitive of that kind, useable for example in

    (the second draft of) the Joy-in-Joy interpreter.

    10 20 30 40 50  [6 five fourth third]  [bare_i  dup *]  map   ==

    10 20 30 40 50  [36 25 400 900]

    Yes, the 10..50 below the list are preserved in spite of all the pops.

    I think this is good behaviour, and should stay like that. On the other

    hand, we do (and should have)

      [five fourth third John]  reverse  ==

      [John third fourth five]

    without evaluation. That means that none of the elements in the

    last list should get evaluated, because John is undefined, and cannot be

    evaluated, and third and third and fourth cannot be evaluated

    when there is nothing like 10..50 below on the stack.

    So five should not be evaluated either.

    On the other hand, all the aggregate combinators (map,fold,filter,split..)

    when applied to list aggregates could do with a "bare_i" version,

    which enforces the evaluation, e.g.

        bare-i-map  ==  [[] cons i] swoncat map

    Alternatively, have a unary list operator

        evaluate  ==  [[] cons i] map

    to be used in

        10 20 30 40 [five 6 third]  evaluate   ==

        10 20 30 40 [5 6 20]

    and then define

        bare-i-map  ==  [evaluate] dip map

    The upshot of this is that the only atoms that should be evaluated

    as the get into the list are the inbuilt CONSTANTS: true, false,

    maxint, setsize etc., and that user defined functions like five,

    fourth and third should not be evaluated.

    Maybe we should also reconsider your earlier on names

    insider sets.

    Comments most welcome

      - Manfred

## John Cowan — 2001-07-02 04:00:44

    Manfred von Thun scripsit:

     > The upshot of this is that the only atoms that should be evaluated

    > as the get into the list are the inbuilt CONSTANTS: true, false,

    > maxint, setsize etc., and that user defined functions like five,

    > fourth and third should not be evaluated.

     Yes, on reflection I agree with this: there should be no built-in constant

    functions in Joy, only constants with various spellings.

    So 5 and true should be on the same level.

    This will take some work to get right.

     > Maybe we should also reconsider your earlier on names

    > inside sets.

     Yes.

    --

    John Cowan                                   cowan@...

    One art/there is/no less/no more/All things/to do/with sparks/galore

    	--Douglas Hofstadter

## Billy Tanksley — 2001-07-02 19:25:45

    From: Manfred von Thun [mailto:phimvt@...]

     >2. It is inelegant and unsafe. Ideally the strings "true" and "false"

    >   (and the half dozen others) should occur only once in the entire

    >   implementation.

     You're expecting map to treat 'true' and 'false' as literals, not functions.

    There's nothing wrong with that; however, why should map (and a few select

    other functions) be the only ones?

    Change your parser; remove 'true' and 'false' from the dictionary, and make

    your lexer recognise them.  'false' should behave EXACTLY the same as '0'

    (or whatever it's equivalent to) in ALL cases.

    One other change would help: a change in your thinking.  Define the meaning

    of a reference to a function, and document the behavior of your built-in

    functions with respect to that.  'true' is a special case (you had defined

    it as a function when you actually wanted a literal), but there are other

    times when you actually WANT a function.

    In other words, your documentation should at least mention what gets left on

    the stack when you type "[dup] first".

     >  - Manfred

     -Billy

## John Cowan — 2001-07-03 02:55:40

    Billy Tanksley scripsit:

     > Change your parser; remove 'true' and 'false' from the dictionary, and make

    > your lexer recognise them.

     I agree.

     > 'false' should behave EXACTLY the same as '0'

    > (or whatever it's equivalent to) in ALL cases.

     It is not equivalent to anything, since Joy has explicitly typed values.

    0 is not 0.0 is not false is not '\0.

     > One other change would help: a change in your thinking.  Define the meaning

    > of a reference to a function, and document the behavior of your built-in

    > functions with respect to that.  'true' is a special case (you had defined

    > it as a function when you actually wanted a literal), but there are other

    > times when you actually WANT a function.

     It would be easy to add two functions "truth" and "falsity" which return

    true and false respectively.  These can be written directly in Joy

    and put into the standard library.

    What I'm not sure about is the proper treatment of "maxint" and "setsize"

    and the others.  They are constants in a particular implementation.

    --

    John Cowan                                   cowan@...

    One art/there is/no less/no more/All things/to do/with sparks/galore

    	--Douglas Hofstadter

## Manfred von Thun — 2001-07-03 03:13:28

    On Mon, 2 Jul 2001, John Cowan wrote:

    [in reply to my thoughts on constants and functions]

    > Yes, on reflection I agree with this: there should be no built-in constant

    > functions in Joy, only constants with various spellings.

    > So 5 and true should be on the same level.

    > This will take some work to get right.

    Ermph, yes, some work indeed. Here are my thoughts:

     1  The internal code that is generated is OK in format, leave it.

     2  Detailed differences between "dup" and "true" ONLY in raw Joy,

        the operator table in file interp.c

     3  The symbol table handles a) raw Joy and b) user defined stuff,

        it has to be consulted when generating code in readfactor.

     4  So, the information in the operator table must get to the

        symbol table either

         a) by copying during initialisation, or

         b) by lookup throughout a session

     5  Currently method 4a is used.

     6  If 4a is continued and more (and more) info is put into the

        operator table, then more (and more) needs to be copied to

        the symbol table (during initialisation).

     7  But the symbol table should not get bigger.

     8  So, method 4b should be used.

     9  For fast lookup during code generation the symbol table contains

        (a pointer to) the strings "dup" "true" etc.

    10  Code generated contains

          a) for raw inbuilts, a pointer to a C-function

          b) for user declared functions, a pointer to Joy code

    11  For 10a the symbol table must access the C-function from the

        operator table.

    12  During initialisation of the symbol table currently

        two kinds of items are copied to the symbol table:

          a) (pointers to the) strings "dup" "true"

          b) the C-code pointer

    13  Instead of 12, to access any information in the operator

        table during code generation, the following should be

        put into the symbol table during initialisation:

          a) as above

          b) a pointer to the relevant record of the operator table.

    14  Change 13 affects code generation in readfactor:

        one extra indirection is needed.

    To do all this, I recommend three stages A B C:

    A   No change in functionality yet, just implement 13 and 14:

        A1. in globals.h a tiny change to declaration of symbol table fields

        A2. in interp.c a tiny change to the loop in inisymtab()

        A3. in utils.c a tiny change in readfactor for code generation

        Now compile and run with just a few tests.

    B   Still no change in functionality:

        B1. in interp.c, a tiny change to declaration of operator table

            fields: at the end add two new fields "typefield"(8bit)

            and "valuefield"(32bit).

        B2. still in interp.c, a BIG change to the declaration the

            operator table details:

             an editor LOOP to add two dummy values 0 and 0 as values

             in the new fields.

             (in other words, replace every  "},  by  ",0,0},

              and don't forget the last:  replace  "}  by  ",0,0}   )

        B3  for the 7 or 8 troublesome constants, change the dummies

            to the real things, so that the operator fields (without

            the help strings) now look like this:

              name     function       typefield       value field

              "dup"    dup_           0               0       (most common)

              "true"   dummy_         BOOLEAN_        1

              "false"  dummy_         BOOLEAN_        0

              "setsize" dummy_        INTEGER_        SETSIZE

        B4. If you were to compile file interp.c now, you should get

            a warning that the functions declared by calls to the PUSH macro

            (true_,false_,setsize_ etc) are not called at all.

            Maybe comment them out at this stage.

    Compile, but there is no need to run.

    C   a tiny final change to achieve the new functionality:

        C1. in file utils.c function readfactor when generating code,

              if (typefield == 0)       generate code as before

                else generate special code in the form

                     typefield     valuefield       next

               e.g.  BOOLEAN_      1                next

                     INTEGER_      32               next

    Compile, test the newly implemented constants outside and inside

    lists, and SMILE.

    This is as far as my thoughts about it have taken me.

    I was supposed to go on a week long holiday, but I will only

    know by Thursday late evening, and then I will leave early

    Friday without being able to say that I cannot do the above

    changes until about two weeks later. So, I'll not do the

    changes in the next two days anyhow. If anybody wants to do them ...

      - Manfred

    BTW Philosophers do not use trig very much, but from what I remember

    (from almost 1/2 C ago),  sin(30.0) = 0.5   tan(45.0) = 1.0   (No ?)

## Manfred von Thun — 2001-07-03 03:39:54

    On Mon, 2 Jul 2001, Billy Tanksley wrote:

     > From: Manfred von Thun [mailto:phimvt@...]

    > >2. It is inelegant and unsafe. Ideally the strings "true" and "false"

    > >   (and the half dozen others) should occur only once in the entire

    > >   implementation.

    >

    > You're expecting map to treat 'true' and 'false' as literals, not functions.

    > There's nothing wrong with that; however, why should map (and a few select

    > other functions) be the only ones?

    >

    > Change your parser; remove 'true' and 'false' from the dictionary, and make

    > your lexer recognise them.

     That is what the quick fix does.

     >  'false' should behave EXACTLY the same as '0'

    > (or whatever it's equivalent to) in ALL cases.

     except when writing:

        true false and.

    should produce

        false

     > One other change would help: a change in your thinking.  Define the meaning

    > of a reference to a function, and document the behavior of your built-in

    > functions with respect to that.  'true' is a special case (you had defined

    > it as a function when you actually wanted a literal), but there are other

    > times when you actually WANT a function.

    >

    > In other words, your documentation should at least mention what gets left on

    > the stack when you type "[dup] first".

     My wording somewhere was unclear, sorry. Which particular documentation

    were you thinking about?

      - Manfred

## Manfred von Thun — 2001-07-03 03:47:42

    On Mon, 2 Jul 2001, John Cowan wrote:

     > Billy Tanksley scripsit:

    >

    > > Change your parser; remove 'true' and 'false' from the dictionary, and make

    > > your lexer recognise them.

    >

    > I agree.

     Except: true and false deserve help strings.

    (And in the suggestions about improved version of the changes which I

    posted just now, the (now modified) dictionary (=optable) entries

    are needed.

     > > 'false' should behave EXACTLY the same as '0'

    > > (or whatever it's equivalent to) in ALL cases.

    >

    > It is not equivalent to anything, since Joy has explicitly typed values.

    > 0 is not 0.0 is not false is not '\0.

    >

    > > One other change would help: a change in your thinking.  Define the meaning

    > > of a reference to a function, and document the behavior of your built-in

    > > functions with respect to that.  'true' is a special case (you had defined

    > > it as a function when you actually wanted a literal), but there are other

    > > times when you actually WANT a function.

    >

    > It would be easy to add two functions "truth" and "falsity" which return

    > true and false respectively.  These can be written directly in Joy

    > and put into the standard library.

     OK, will do.

     > What I'm not sure about is the proper treatment of "maxint" and "setsize"

    > and the others.  They are constants in a particular implementation.

     I am suggesting that they be treated as implementation dependent

    constants, unlike "true" and "false".

      - Manfred