# function/object ambiguity + quotation alternative

## John Nowak — 2009-02-26 14:34:38

    I've hinted at this recently, but never properly explained it. It may

    be entirely uninteresting or even an incorrect observation, so I'd

    appreciate a whack on the hand if I'm off track. I think, however,

    that it may be important in letting us further develop a firm

    theoretical basis for concatenative languages.

    In a concatenative language, all terms denote functions. I don't think

    this is too contentious to say. For example, '42' denotes the function

    that pushes the value 42 onto a stack. '[foo bar]' is a function that

    pushes the quotation/list [foo bar] onto the stack. Et cetera.

    This seem to be a unique property. I have never seen a non-

    concatenative language in which every term denoted a function.

    John Backus invented the term "function-level programming", of which

    his language FP is the canonical example. In FP however, the term '42'

    represents an object. You use the combining form '~', aka "constant",

    to produce a function that returns the object 42 when passed any

    value, e.g. '~42'.

    Assume application is written ":", composition is written ".", a list

    is written in angle brackets, and construction is written with square

    brackets. Given this, the semantics of 'dup' in FP are as follows:

        dup:X   ->  <X, X>

        dup.~X  ==  [~X, ~X]

    The former gives the semantics of applying 'dup' to some object X. The

    latter states an equivalence between composing 'dup' with the constant

    function '~X' and construction over two functions that are both the

    constant function '~X'.

    With concatenative languages, we always use the second form for

    expressing the semantics of some function, e.g. 'X dup == X X'. We do

    this because we have no syntax for application and no way of

    expressing objects. There's something strange here though. Because all

    terms denote functions, 'X' must be a function. However, 'X' cannot be

    any function; it must be a function that pushes a value (and always

    the same value) onto a stack.

    I'm now wondering if this function/object ambiguity in concatenative

    languages is really a good thing. Take the Joy expression '[1 2 3]'.

    We can say that '[1 2 3]' is a function that pushes the value [1 2 3]

    onto a stack, but we also have to say that the term '1' within the

    term '[1 2 3]' itself denotes a function. This seems strange because,

    if you gets the first element of the list, you certainly can't use it

    as a function; it's a number.

    This strangeness is more evident in the following example. The

    expression '[dup swap] head' yields 'dup', but 'dup != [dup swap]

    head'! This is because the left side of the equality is the *function*

    'dup', but the right side gets reduced to the *object* 'dup'. You

    might think this problem is due to Joy's "open" quotations, but you

    have the same problem in Factor. For example, 'sq != { sq } first'

    despite the fact that '{ sq } first' yields sq!

    I believe I know how to solve this problem: Get rid of the function/

    object ambiguity.

    To do this, we drop the requirement that all terms denote functions.

    '42' will now denote the *number* 42. To push 42 onto the stack, we'll

    write '`42', i.e. the push function '`' applied to the object 42.

    The presence of '`' allows us to get rid of quotation. Instead of '[+]

    map', we would write '`+ map'; the '`' function applied to the '+'

    function yields a new function that pushes the '+' function onto a

    stack. We'd also need to add parentheses for grouping; you'd write

    '`(foo bar)' instead of '[foo bar]'.

    This allows us a solution to the problem with Factor's array literals

    shown above: Array literals would only be allowed to contain terms

    representing objects. For example, '`{ 42 `42 }' would be a function

    that pushes an array onto a stack where the first element of the array

    is the number 42 and the second element is a function that pushes 42

    onto a stack.

    I would also suggest adding an additional array syntax that takes

    *functions* that evaluate to single objects. If 'x' is defined as '1 2

    drop', then we could write '{| x |}' to push an array of one element

    containing the number 1 onto the stack. Alternatively, because we now

    have parentheses for grouping, we could replace 'x' with its

    definition and write '{| ( 1 2 drop ) |}' instead.

    In Joy, where creating multiple "copies" of the stack is cheap, you

    could use my parallel "banana" combinator to construct lists. For

    example, you could write the function '2 3 (|+ -|)' which would be

    equivalent to the function '`{5 -1}' (assuming we also adopted closed

    quotations for Joy and added '{ }' as a list literal syntax).

    Since we have lost the object/function ambiguity, we can now express

    the semantics of our functions in terms of application. I propose the

    syntax '<object>:<function>' to indicate an application. Assuming our

    concatenative language is stack-based, the object will always be a

    stack.

    I represent the stack as a null-terminated list (using angle brackets)

    which is necessary to show how the function in question handles the

    "rest of the stack". The right-most element of a list is the "top"

    element. '<>' denotes the null list.

    Here are the semantics of six functions in terms of application:

        R:`42  ->  <R, 42>

        <R,X>:dup  ->  <R,<X,X>>

        <R,<X,Y>>:swap  ->  <R,<Y,X>>

        <R,F>:i  ->  R:F

        <R,<X,F>>:dip  ->  <R:F, X>

        R:clear  ->  <>

    Alternatively, we can express our semantics in terms of equivalencies.

    This isn't as generally useful as the application form above (e.g. you

    can't express 'clear' in this form), but it is perhaps a bit easier to

    read:

        `42  ==  `42

        `X dup  ==  `X `X

        `X `Y swap  ==  `Y `X

        `F i  ==  F

        `X `F dip  ==  F `X

    If you made it this far, thank you. Any thoughts would be appreciated.

    - John

## Stevan Apter — 2009-02-26 15:21:30

    > This strangeness is more evident in the following example. The

    > expression '[dup swap] head' yields 'dup', but 'dup != [dup swap]

    > head'! This is because the left side of the equality is the *function*

    > 'dup', but the right side gets reduced to the *object* 'dup'.

     i've always assumed that [dup swap] head is the function dup.  e.g. in XY:

      2 [dup swap] first i

    2 2

    that is, [dup swap] first leaves the function dup on the stack.

    then i moves the top item of the stack to the head of the queue.

    what am i missing?

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

    From: "John Nowak" <john@...>

    To: "concatenative" <concatenative@yahoogroups.com>

    Sent: Thursday, February 26, 2009 9:34 AM

    Subject: [stack] function/object ambiguity + quotation alternative

    > I've hinted at this recently, but never properly explained it. It may

    > be entirely uninteresting or even an incorrect observation, so I'd

    > appreciate a whack on the hand if I'm off track. I think, however,

    > that it may be important in letting us further develop a firm

    > theoretical basis for concatenative languages.

    >

    > In a concatenative language, all terms denote functions. I don't think

    > this is too contentious to say. For example, '42' denotes the function

    > that pushes the value 42 onto a stack. '[foo bar]' is a function that

    > pushes the quotation/list [foo bar] onto the stack. Et cetera.

    >

    > This seem to be a unique property. I have never seen a non-

    > concatenative language in which every term denoted a function.

    >

    > John Backus invented the term "function-level programming", of which

    > his language FP is the canonical example. In FP however, the term '42'

    > represents an object. You use the combining form '~', aka "constant",

    > to produce a function that returns the object 42 when passed any

    > value, e.g. '~42'.

    >

    > Assume application is written ":", composition is written ".", a list

    > is written in angle brackets, and construction is written with square

    > brackets. Given this, the semantics of 'dup' in FP are as follows:

    >

    >    dup:X   ->  <X, X>

    >    dup.~X  ==  [~X, ~X]

    >

    > The former gives the semantics of applying 'dup' to some object X. The

    > latter states an equivalence between composing 'dup' with the constant

    > function '~X' and construction over two functions that are both the

    > constant function '~X'.

    >

    > With concatenative languages, we always use the second form for

    > expressing the semantics of some function, e.g. 'X dup == X X'. We do

    > this because we have no syntax for application and no way of

    > expressing objects. There's something strange here though. Because all

    > terms denote functions, 'X' must be a function. However, 'X' cannot be

    > any function; it must be a function that pushes a value (and always

    > the same value) onto a stack.

    >

    > I'm now wondering if this function/object ambiguity in concatenative

    > languages is really a good thing. Take the Joy expression '[1 2 3]'.

    > We can say that '[1 2 3]' is a function that pushes the value [1 2 3]

    > onto a stack, but we also have to say that the term '1' within the

    > term '[1 2 3]' itself denotes a function. This seems strange because,

    > if you gets the first element of the list, you certainly can't use it

    > as a function; it's a number.

    >

    > This strangeness is more evident in the following example. The

    > expression '[dup swap] head' yields 'dup', but 'dup != [dup swap]

    > head'! This is because the left side of the equality is the *function*

    > 'dup', but the right side gets reduced to the *object* 'dup'. You

    > might think this problem is due to Joy's "open" quotations, but you

    > have the same problem in Factor. For example, 'sq != { sq } first'

    > despite the fact that '{ sq } first' yields sq!

    >

    > I believe I know how to solve this problem: Get rid of the function/

    > object ambiguity.

    >

    > To do this, we drop the requirement that all terms denote functions.

    > '42' will now denote the *number* 42. To push 42 onto the stack, we'll

    > write '`42', i.e. the push function '`' applied to the object 42.

    >

    > The presence of '`' allows us to get rid of quotation. Instead of '[+]

    > map', we would write '`+ map'; the '`' function applied to the '+'

    > function yields a new function that pushes the '+' function onto a

    > stack. We'd also need to add parentheses for grouping; you'd write

    > '`(foo bar)' instead of '[foo bar]'.

    >

    > This allows us a solution to the problem with Factor's array literals

    > shown above: Array literals would only be allowed to contain terms

    > representing objects. For example, '`{ 42 `42 }' would be a function

    > that pushes an array onto a stack where the first element of the array

    > is the number 42 and the second element is a function that pushes 42

    > onto a stack.

    >

    > I would also suggest adding an additional array syntax that takes

    > *functions* that evaluate to single objects. If 'x' is defined as '1 2

    > drop', then we could write '{| x |}' to push an array of one element

    > containing the number 1 onto the stack. Alternatively, because we now

    > have parentheses for grouping, we could replace 'x' with its

    > definition and write '{| ( 1 2 drop ) |}' instead.

    >

    > In Joy, where creating multiple "copies" of the stack is cheap, you

    > could use my parallel "banana" combinator to construct lists. For

    > example, you could write the function '2 3 (|+ -|)' which would be

    > equivalent to the function '`{5 -1}' (assuming we also adopted closed

    > quotations for Joy and added '{ }' as a list literal syntax).

    >

    > Since we have lost the object/function ambiguity, we can now express

    > the semantics of our functions in terms of application. I propose the

    > syntax '<object>:<function>' to indicate an application. Assuming our

    > concatenative language is stack-based, the object will always be a

    > stack.

    >

    > I represent the stack as a null-terminated list (using angle brackets)

    > which is necessary to show how the function in question handles the

    > "rest of the stack". The right-most element of a list is the "top"

    > element. '<>' denotes the null list.

    >

    > Here are the semantics of six functions in terms of application:

    >

    >    R:`42  ->  <R, 42>

    >    <R,X>:dup  ->  <R,<X,X>>

    >    <R,<X,Y>>:swap  ->  <R,<Y,X>>

    >    <R,F>:i  ->  R:F

    >    <R,<X,F>>:dip  ->  <R:F, X>

    >    R:clear  ->  <>

    >

    > Alternatively, we can express our semantics in terms of equivalencies.

    > This isn't as generally useful as the application form above (e.g. you

    > can't express 'clear' in this form), but it is perhaps a bit easier to

    > read:

    >

    >    `42  ==  `42

    >    `X dup  ==  `X `X

    >    `X `Y swap  ==  `Y `X

    >    `F i  ==  F

    >    `X `F dip  ==  F `X

    >

    > If you made it this far, thank you. Any thoughts would be appreciated.

    >

    > - John

    >

## John Nowak — 2009-02-26 15:47:41

    On Feb 26, 2009, at 10:21 AM, Stevan Apter wrote:

     >> This strangeness is more evident in the following example. The

    >> expression '[dup swap] head' yields 'dup', but 'dup != [dup swap]

    >> head'! This is because the left side of the equality is the

    >> *function*

    >> 'dup', but the right side gets reduced to the *object* 'dup'.

    >

    > i've always assumed that [dup swap] head is the function dup.  e.g.

    > in XY:

    >

    >  2 [dup swap] first i

    > 2 2

    >

    > that is, [dup swap] first leaves the function dup on the stack.

    > then i moves the top item of the stack to the head of the queue.

    >

    > what am i missing?

     I don't know XY, but XY does not work the same way as Joy and Factor

    apparently.

    Factor:

         >> 5 { dup } first call

         Generic word call does not define a method for the word class.

        Dispatching on object: dup

    Joy:

         >> 5 [dup] first i

         run time error: quotation as top parameter needed for i

    This is the problem I'm referring to.

    What XY does seems even worse though! Here's why:

        1. [dup] i == [dup] first i  (given, as per your example)

        2. [dup] == [dup] first      (removing shared 'i' suffix)

        3. id == first               (removing share '[dup]' prefix)

    Certainly first cannot be the identity function! Is the algebra of XY

    broken? Am I missing something?

    - John

## John Nowak — 2009-02-26 16:21:14

    On Feb 26, 2009, at 10:47 AM, John Nowak wrote:

     > This is the problem I'm referring to.

     Maybe this is an even simpler way of stating the problem in Joy and

    Factor, where '->' means "evaluates to":

        1. [X] first    ->  X    (given)

        2. [dup] first  ->  dup  (valid, following from 1)

        3. [dup] first  !=  dup  (given, in contradiction to 2)

    The problem is that the 'dup' on the right side of 2 is a function

    reified as an object, but the 'dup' on the right side of 3 is a

    function. 'dup' "the function" is not the same as 'dup' "the function

    object", yet they are represented by the same term. This causes

    problems with algebraic manipulation of programs as plainly seen

    above. My solution is to get rid of this ambiguity.

    - John

## Stevan Apter — 2009-02-26 17:22:22

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Thursday, February 26, 2009 10:47 AM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    > On Feb 26, 2009, at 10:21 AM, Stevan Apter wrote:

    >

    >>> This strangeness is more evident in the following example. The

    >>> expression '[dup swap] head' yields 'dup', but 'dup != [dup swap]

    >>> head'! This is because the left side of the equality is the

    >>> *function*

    >>> 'dup', but the right side gets reduced to the *object* 'dup'.

    >>

    >> i've always assumed that [dup swap] head is the function dup.  e.g.

    >> in XY:

    >>

    >>  2 [dup swap] first i

    >> 2 2

    >>

    >> that is, [dup swap] first leaves the function dup on the stack.

    >> then i moves the top item of the stack to the head of the queue.

    >>

    >> what am i missing?

    >

    > I don't know XY, but XY does not work the same way as Joy and Factor

    > apparently.

    >

    > Factor:

    >

    >    >> 5 { dup } first call

    >    Generic word call does not define a method for the word class.

    >    Dispatching on object: dup

    >

    > Joy:

    >

    >    >> 5 [dup] first i

    >    run time error: quotation as top parameter needed for i

    >

    > This is the problem I'm referring to.

    >

    > What XY does seems even worse though! Here's why:

    >

    >    1. [dup] i == [dup] first i  (given, as per your example)

    >    2. [dup] == [dup] first      (removing shared 'i' suffix)

    no.  dup = [dup] first.

    >    3. id == first               (removing share '[dup]' prefix)

    >

    > Certainly first cannot be the identity function! Is the algebra of XY

    > broken? Am I missing something?

    >

    > - John

    >

## William Tanksley — 2009-02-26 17:44:54

    Stevan Apter wrote:

     > From: "John Nowak" <john@...>

    > > What XY does seems even worse though! Here's why:

    > >    1. [dup] i == [dup] first i  (given, as per your example)

    > >    2. [dup] == [dup] first      (removing shared 'i' suffix)

    >>    3. id == first               (removing share '[dup]' prefix)

    > no.  dup = [dup] first.

     You're right, but he's also right -- you should always be able to remove

    identical suffixes from both sides of the equation, and in this case you

    can't do that.

    -Wm

## John Nowak — 2009-02-26 17:45:45

    On Feb 26, 2009, at 12:22 PM, Stevan Apter wrote:

     >>   2. [dup] == [dup] first      (removing shared 'i' suffix)

    >

    > no.  dup = [dup] first.

     You're missing the point. I know that 'dup = [dup] first', but I can

    prove '[dup] == [dup] first'!

    I'll start with your example (minus the swap); after each step, I'll

    indicate how I came upon the given equality:

    1. 2 [dup] first i == 2 2        (given)

    2. [F] i == F                    (given)

    3  2 dup == 2 2                  (given)

    4. 2 [dup] i == 2 2              (2+3: substituted '[dup] i' for 'dup')

    5. 2 [dup] i == 2 [dup] first i  (1+4: both equal '2 2')

    6. i == first i                  (5: removed shared '2 [dup]' prefix)

    7. id == first                   (6: removed 'i' suffix)

    To repeat, I know this is a bogus conclusion; that's my point. The

    problem arises from the fact that '[dup] i' functions identically to

    '[dup] first i' in XY; or, at least that's my understanding.

    If my little derivation is wrong, please correct me. If not, I believe

    this to be a problem in XY's semantics.

    - John

## John Nowak — 2009-02-26 17:53:44

    On Feb 26, 2009, at 12:45 PM, John Nowak wrote:

     >

    > On Feb 26, 2009, at 12:22 PM, Stevan Apter wrote:

    >

    >>>  2. [dup] == [dup] first      (removing shared 'i' suffix)

    >>

    >> no.  dup = [dup] first.

    >

    > You're missing the point. I know that 'dup = [dup] first', but I can

    > prove '[dup] == [dup] first'!

     To be more precise, I know '[dup] first' evaluates to the function

    object 'dup'. I assume this is what you mean.

    That said, the function 'dup' does *not* equal the function '[dup]

    first'. Obviously '2 dup' yields a different answer than '2 [dup]

    first'. This is the initial problem I brought up and it may affect XY;

    I know it affects Joy and Factor. The ability to prove '[dup] == [dup]

    first' is an additional issue that is XY-specific.

    - John

## Stevan Apter — 2009-02-26 18:06:09

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Thursday, February 26, 2009 12:45 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    > On Feb 26, 2009, at 12:22 PM, Stevan Apter wrote:

    >

    >>>   2. [dup] == [dup] first      (removing shared 'i' suffix)

    >>

    >> no.  dup = [dup] first.

    >

    > You're missing the point. I know that 'dup = [dup] first', but I can

    > prove '[dup] == [dup] first'!

    >

    > I'll start with your example (minus the swap); after each step, I'll

    > indicate how I came upon the given equality:

    >

    > 1. 2 [dup] first i == 2 2        (given)

    > 2. [F] i == F                    (given)

    > 3  2 dup == 2 2                  (given)

    > 4. 2 [dup] i == 2 2              (2+3: substituted '[dup] i' for 'dup')

    > 5. 2 [dup] i == 2 [dup] first i  (1+4: both equal '2 2')

    > 6. i == first i                  (5: removed shared '2 [dup]' prefix)

    > 7. id == first                   (6: removed 'i' suffix)

    >

    > To repeat, I know this is a bogus conclusion; that's my point. The

    > problem arises from the fact that '[dup] i' functions identically to

    > '[dup] first i' in XY; or, at least that's my understanding.

    >

    > If my little derivation is wrong, please correct me. If not, I believe

    > this to be a problem in XY's semantics.

    i see the problem.  in XY, [X]first != [X]i.

    i moves the top of the stack to the head of the queue, whence it executes,

    immediately.

    first replaces the top of the stack with the first element of the top of

    the stack.

    to make things just a little more confusing, there is no stack underflow

    in XY, so e.g.

        [dup] first i = [{ a \ a \ a }]

    and:

        10 20 [dup] [i] infra = 10 20 [[{ a \ a \ a }]]

    which is the unit list of dup's "object code".  repeatedly applying i

    to this has no effect.

    but:

        [dup] first i 10 swap i = 10 10

    but this is an implementation detail.  an underflow exception could be

    thrown instead.

    >

    > - John

    >

## Stevan Apter — 2009-02-26 18:09:25

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

    From: "William Tanksley" <wtanksleyjr@...>

    To: <concatenative@yahoogroups.com>

    Sent: Thursday, February 26, 2009 12:44 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    > Stevan Apter wrote:

    >> From: "John Nowak" <john@...>

    >> > What XY does seems even worse though! Here's why:

    >> >    1. [dup] i == [dup] first i  (given, as per your example)

    >> >    2. [dup] == [dup] first      (removing shared 'i' suffix)

    >>>    3. id == first               (removing share '[dup]' prefix)

    >

    >> no.  dup = [dup] first.

    >

    > You're right, but he's also right -- you should always be able to remove

    > identical suffixes from both sides of the equation, and in this case you

    > can't do that.

    1 is true, 2 is false.

    first != i != id

    i don't see the problem.

    >

    > -Wm

    >

    >

    >

## Stevan Apter — 2009-02-26 18:13:17

    if you search way back in the archives, you'll see that this problem

    surfaced fairly early on.  billy and i batted around the idea that the

    evaluator could be made "voracious":

        2 [dup] first -> 2 2

    i.e. the evaluator would not abide naked functions on the stack; it

    would apply repeatedly until that was not the case.

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Thursday, February 26, 2009 12:53 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    > On Feb 26, 2009, at 12:45 PM, John Nowak wrote:

    >

    >>

    >> On Feb 26, 2009, at 12:22 PM, Stevan Apter wrote:

    >>

    >>>>  2. [dup] == [dup] first      (removing shared 'i' suffix)

    >>>

    >>> no.  dup = [dup] first.

    >>

    >> You're missing the point. I know that 'dup = [dup] first', but I can

    >> prove '[dup] == [dup] first'!

    >

    > To be more precise, I know '[dup] first' evaluates to the function

    > object 'dup'. I assume this is what you mean.

    >

    > That said, the function 'dup' does *not* equal the function '[dup]

    > first'. Obviously '2 dup' yields a different answer than '2 [dup]

    > first'. This is the initial problem I brought up and it may affect XY;

    > I know it affects Joy and Factor. The ability to prove '[dup] == [dup]

    > first' is an additional issue that is XY-specific.

    >

    > - John

    >

## John Nowak — 2009-02-26 18:22:08

    On Feb 26, 2009, at 1:06 PM, Stevan Apter wrote:

     > i see the problem.  in XY, [X]first != [X]i.

    > i moves the top of the stack to the head of the queue, whence it

    > executes,

    > immediately.

    > first replaces the top of the stack with the first element of the

    > top of

    > the stack.

     Your assessment that the problem is '[X]first != [X]i' is incorrect.

    Currently in XY, this is true:

        [dup] first i  ==  [dup] i

    The problem is that this means I can prove that 'first' is the

    identity function.

    If we change XY such that '[dup] first == [dup] i', I can take this:

        [dup] first i  ==  [dup] i

    And substitute '[dup] i' for '[dup] first':

        [dup] i i  ==  [dup] i

    And hence I can prove 'i i == i', and then from there prove that 'i'

    is the identity function.

    The only way to solve this problem is to have '[dup] first i' cause an

    error. 'i' must be correctly restricted to performing "dequotation" as

    in Joy, Factor, Cat, etc.

    - John

## Christopher Diggins — 2009-02-26 19:57:15

    >> the evaluator would not abide naked functions on the stack; it would apply repeatedly until that was not the case.

     Then you have a first order language. I don't really see what that

    buys you. Why not allow functions on the stack? It seems to me that

    higher-order languages are only a positive thing. Joy and its ilk are

    only interesting to me because they allow functions on the stack.

## John Nowak — 2009-02-26 20:08:19

    On Feb 26, 2009, at 2:57 PM, Christopher Diggins wrote:

     >>> the evaluator would not abide naked functions on the stack; it

    >>> would apply repeatedly until that was not the case.

    >

    > Then you have a first order language. I don't really see what that

    > buys you. Why not allow functions on the stack?

     I think you're misunderstanding what Stevan was saying. Stevan is not

    suggesting anything that would eliminate quotations or make a language

    first order.

    Joy and XY have "open" quotations. You can modify them as if they were

    lists. This causes two problems.

    The first is that the language becomes non-extensional. For example,

    say you know that 'a b == c d'. In Joy and XY, it does not follow that

    '[a b] == [c d]' as it does in Cat.

    The second problem is that, because you can take "things" out of a

    quotation, you end up with weird problems. Factor has this problem too

    with its array literals; or at least I'm pretty sure it does.

    Take the program '5 [dup] first' for example. The result of this is '5

    dup'. However, the 'dup' here is *not* a function the same way 'first'

    was; it's a function object. Accordingly, the result of evaluation '5

    [dup]' is a stack with two elements; the first is the value 5 and the

    second is the value 'dup'.

    What Stevan was suggesting was to evaluate "unquoted function objects"

    like 'dup' in the example above. In this system '5 [dup] first' would

    reduce to '5 dup', but then further reduce to '5 5' without the need

    to explicitly re-quote 'dup' and call 'i'.

     > It seems to me that higher-order languages are only a positive thing.

     Certain forms of reasoning are a lot easier without higher order

    functions. It's a tradeoff.

    - John

## Stevan Apter — 2009-02-26 20:11:20

    i don't disagree.  so in cat, what's on the stack after evaluating [dup]first?

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

    From: "Christopher Diggins" <cdiggins@...>

    To: <concatenative@yahoogroups.com>

    Sent: Thursday, February 26, 2009 2:57 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >>> the evaluator would not abide naked functions on the stack; it would apply repeatedly until that was not the case.

    >

    > Then you have a first order language. I don't really see what that

    > buys you. Why not allow functions on the stack? It seems to me that

    > higher-order languages are only a positive thing. Joy and its ilk are

    > only interesting to me because they allow functions on the stack.

    >

## John Nowak — 2009-02-26 20:10:27

    On Feb 26, 2009, at 3:08 PM, John Nowak wrote:

     > Accordingly, the result of evaluation '5 [dup]' is a stack with two

    > elements; the first is the value 5 and the  second is the value 'dup'.

     Sorry, that should read as follows:

    "Accordingly, the result of evaluation '5 [dup] first' is a stack with

    two elements; the first is the value 5 and the second is the value dup."

    - John

## John Nowak — 2009-02-26 20:15:06

    On Feb 26, 2009, at 3:11 PM, Stevan Apter wrote:

     >>> the evaluator would not abide naked functions on the stack; it

    >>> would apply repeatedly until that was not the case.

    >>

    >> Then you have a first order language. I don't really see what that

    >>

    >> buys you. Why not allow functions on the stack? It seems to me that

    >> higher-order languages are only a positive thing. Joy and its ilk are

    >> only interesting to me because they allow functions on the stack.

    >

    > i don't disagree.

     You should disagree unless you're suggesting that '5 [dup]' evaluate

    to '5 5'. Are you? I wasn't under the impression that you meant to

    make that point. If you weren't suggesting that, the language would

    remain higher-order.

     > so in cat, what's on the stack after evaluating [dup]first?

     This is not possible in Cat because quotations are not manipulatable

    as such. This is necessary to preserve extensionality (e.g. '[1 2

    drop] == [1]') and to allow the language to be typed.

    - John

## Stevan Apter — 2009-02-26 20:25:00

    well, it's worth pointing out that

        5 [dup] first i

        5 [dup] i

    both evaluate to 5 5 in XY because 'i' doesn't quite mean

    disquotation.  it means "take the top of the stack and

    prepend it to the head of the queue."  where Q is the queue

    and S is the stack, the k code which implements this is

    roughly:

        Q:(last S),Q

        S:-1_S

    x,y is concatenation, x_y is drop from the head or tail.

    suppose last S = dup, then Q = dup,Q.  suppose last S = [dup],

    then Q = [dup],Q.  but Q is the same in both cases.  concatenation

    of a unit list is the same as the concatenation of atom.

    if i can remember what i was thinking at the time, it was

    something like this:  i want to be able to put naked functions

    on the stack.  but i also want to be able to evaluate them

    once they're there.  so reinterpret 'i' to mean 'move to the

    queue'.

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Thursday, February 26, 2009 3:08 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    > On Feb 26, 2009, at 2:57 PM, Christopher Diggins wrote:

    >

    >>>> the evaluator would not abide naked functions on the stack; it

    >>>> would apply repeatedly until that was not the case.

    >>

    >> Then you have a first order language. I don't really see what that

    >> buys you. Why not allow functions on the stack?

    >

    > I think you're misunderstanding what Stevan was saying. Stevan is not

    > suggesting anything that would eliminate quotations or make a language

    > first order.

    >

    > Joy and XY have "open" quotations. You can modify them as if they were

    > lists. This causes two problems.

    >

    > The first is that the language becomes non-extensional. For example,

    > say you know that 'a b == c d'. In Joy and XY, it does not follow that

    > '[a b] == [c d]' as it does in Cat.

    >

    > The second problem is that, because you can take "things" out of a

    > quotation, you end up with weird problems. Factor has this problem too

    > with its array literals; or at least I'm pretty sure it does.

    >

    > Take the program '5 [dup] first' for example. The result of this is '5

    > dup'. However, the 'dup' here is *not* a function the same way 'first'

    > was; it's a function object. Accordingly, the result of evaluation '5

    > [dup]' is a stack with two elements; the first is the value 5 and the

    > second is the value 'dup'.

    >

    > What Stevan was suggesting was to evaluate "unquoted function objects"

    > like 'dup' in the example above. In this system '5 [dup] first' would

    > reduce to '5 dup', but then further reduce to '5 5' without the need

    > to explicitly re-quote 'dup' and call 'i'.

    >

    >> It seems to me that higher-order languages are only a positive thing.

    >

    > Certain forms of reasoning are a lot easier without higher order

    > functions. It's a tradeoff.

    >

    > - John

    >

## Stevan Apter — 2009-02-26 20:33:39

    i meant that i don't disagree that functions on the stack are a

    good thing.

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Thursday, February 26, 2009 3:15 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    > On Feb 26, 2009, at 3:11 PM, Stevan Apter wrote:

    >

    >>>> the evaluator would not abide naked functions on the stack; it

    >>>> would apply repeatedly until that was not the case.

    >>>

    >>> Then you have a first order language. I don't really see what that

    >>>

    >>> buys you. Why not allow functions on the stack? It seems to me that

    >>> higher-order languages are only a positive thing. Joy and its ilk are

    >>> only interesting to me because they allow functions on the stack.

    >>

    >> i don't disagree.

    >

    > You should disagree unless you're suggesting that '5 [dup]' evaluate

    > to '5 5'. Are you? I wasn't under the impression that you meant to

    > make that point. If you weren't suggesting that, the language would

    > remain higher-order.

    >

    >> so in cat, what's on the stack after evaluating [dup]first?

    >

    > This is not possible in Cat because quotations are not manipulatable

    > as such. This is necessary to preserve extensionality (e.g. '[1 2

    > drop] == [1]') and to allow the language to be typed.

    >

    > - John

    >

## Don Groves — 2009-02-26 21:04:33

    On Feb 26, 2009, at 11:57 AM, Christopher Diggins wrote:

     >>> the evaluator would not abide naked functions on the stack; it

    >>> would apply repeatedly until that was not the case.

    >

    > Then you have a first order language. I don't really see what that

    > buys you. Why not allow functions on the stack? It seems to me that

    > higher-order languages are only a positive thing. Joy and its ilk are

    > only interesting to me because they allow functions on the stack.

     I'll second that.

    --

    don

## William Tanksley — 2009-02-26 21:19:41

    Don Groves wrote:

     > Christopher Diggins wrote:

    > >>> the evaluator would not abide naked functions on the stack; it

    > >>> would apply repeatedly until that was not the case.

    > > Then you have a first order language. I don't really see what that

    > > buys you. Why not allow functions on the stack? It seems to me that

    > > higher-order languages are only a positive thing. Joy and its ilk are

    > > only interesting to me because they allow functions on the stack.

    > I'll second that.

     You guys must be high(er order). (Don, I'm not sure if that pun was

    actually intended. If it wasn't, sorry I misunderstood you, and my reply

    was a pun.)

    Higher order languages are cool, but first order languages can be useful

    too; FP (AFAIK) is a first-order language, as is (I believe) APL, J, and

    NIAL. So's Forth, although being impure it doesn't try to restrict that

    in any way (you can kind of play with function references).

     > don

     -Wm

## Don Groves — 2009-02-26 21:25:56

    On Feb 26, 2009, at 1:19 PM, William Tanksley wrote:

     > Don Groves wrote:

    >> Christopher Diggins wrote:

    >>>>> the evaluator would not abide naked functions on the stack; it

    >>>>> would apply repeatedly until that was not the case.

    >

    >>> Then you have a first order language. I don't really see what that

    >>> buys you. Why not allow functions on the stack? It seems to me that

    >>> higher-order languages are only a positive thing. Joy and its ilk

    >>> are

    >>> only interesting to me because they allow functions on the stack.

    >

    >> I'll second that.

    >

    > You guys must be high(er order). (Don, I'm not sure if that pun was

    > actually intended. If it wasn't, sorry I misunderstood you, and my

    > reply

    > was a pun.)

     It was, and it wasn't -- I left it up to the reader.

    Yours definitely was -- and a good one too ;-)

     > Higher order languages are cool, but first order languages can be

    > useful

    > too; FP (AFAIK) is a first-order language, as is (I believe) APL, J,

    > and

    > NIAL. So's Forth, although being impure it doesn't try to restrict

    > that

    > in any way (you can kind of play with function references).

     I did a lot of that in Forth, but it's much nicer to have it part

    of the language rather than a kludge.

    --

    don

     >> don

    >

    > -Wm

    >

    >

    >

    >

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

    >

    > Yahoo! Groups Links

    >

    >

    >

## Chris Double — 2009-02-26 22:12:39

    On Fri, Feb 27, 2009 at 9:25 AM, Stevan Apter <sa@...> wrote:

     > if i can remember what i was thinking at the time, it was

    > something like this: i want to be able to put naked functions

    > on the stack. but i also want to be able to evaluate them

    > once they're there. so reinterpret 'i' to mean 'move to the

    > queue'.

     This is one of the features I like about XY.That function objects are

    executable using 'i' just like quotations. It's a feature that has

    been discussed to be added to factor occasionally, that of making word

    objects callable (ie. make call a generic that works on quotations and

    words).

    Chris.

    --

    http://www.bluishcoder.co.nz

## zallambo — 2009-02-27 00:02:32

    --- In concatenative@yahoogroups.com, William Tanksley

    <wtanksleyjr@...> wrote:

     >

    > Stevan Apter wrote:

    > > From: "John Nowak" <john@...>

    > > > What XY does seems even worse though! Here's why:

    > > >    1. [dup] i == [dup] first i  (given, as per your example)

    > > >    2. [dup] == [dup] first      (removing shared 'i' suffix)

    > >>    3. id == first               (removing share '[dup]' prefix)

    >

    > > no.  dup = [dup] first.

    >

    > You're right, but he's also right -- you should always be able to remove

    > identical suffixes from both sides of the equation, and in this case you

    > can't do that.

    >

    > -Wm

    >

     (2) does not follow from (1) and (3) does not follow from (2). In

    general, you *cannot* remove common prefixes and suffixes. For instance,

    If you could remove prefixes, then

       [dup] dup == [dup] [dup]

    => dup == [dup].

    If you could remove suffixes, then

       2 [id] i == 1 [inc] i

    => 2 [id] == 1 [inc].

    There's nothing special about concatenative languages in this regard;

    as long as there are functions that aren't reversible (i.e. are not

    one-to-one and onto), f(a) = f(b) does not imply a = b. And f(a) =

    g(a) does not imply f = g.

    I think John has a point though. We need a way to distinguish between

    the function 'dup' and the object 'dup'. I suggest putting a single

    quote in front of objects, like symbols in Scheme. So

    [dup] i == dup

    [dup] first == 'dup

    However, we *don't* need to distinguish the number 42 from the

    function 42. Pushing the number 42 on the stack is exactly the same as

    applying the function 42 to the stack. So

    [42] i == [42] first

    42 == '42

    Does anyone have another syntax for writing 'dup? I cannot recall

    seeing any.

    Justin

## Adam — 2009-02-27 02:58:10

    John,

    Are you aware of the word execute

    (http://docs.factorcode.org/content/word-execute,words.html)?

    If I understand Chris, the current call/execute distinction reveals your

    problem but I'm not sure.

    ( scratchpad ) 5 { dup } first execute . .

    5

    5

    ( scratchpad ) 5 { dup } >quotation call . .

    5

    5

    ( scratchpad ) 5 [ dup ] first execute . .

    5

    5

    ( scratchpad ) 5 [ dup ] call . .

    5

    5

    ( scratchpad ) 5 \ dup execute . .

    5

    5

    -Adam

    --- In concatenative@yahoogroups.com, Chris Double <chris.double@...>

    wrote:

     >

    > On Fri, Feb 27, 2009 at 9:25 AM, Stevan Apter sa@... wrote:

    > > if i can remember what i was thinking at the time, it was

    > > something like this: i want to be able to put naked functions

    > > on the stack. but i also want to be able to evaluate them

    > > once they're there. so reinterpret 'i' to mean 'move to the

    > > queue'.

    >

    > This is one of the features I like about XY.That function objects are

    > executable using 'i' just like quotations. It's a feature that has

    > been discussed to be added to factor occasionally, that of making word

    > objects callable (ie. make call a generic that works on quotations and

    > words).

    >

    > Chris.

    > --

    > http://www.bluishcoder.co.nz

    >

## John Cowan — 2009-02-27 05:05:18

    John Nowak scripsit:

     > In a concatenative language, all terms denote functions. I don't think

    > this is too contentious to say. For example, '42' denotes the function

    > that pushes the value 42 onto a stack. '[foo bar]' is a function that

    > pushes the quotation/list [foo bar] onto the stack. Et cetera.

     For Joy, at least, you can go further: *everything* is simultaneously a

    value and a function.  Thus '+' is both a value (a symbol, specifically)

    and the addition function.  The difference between symbols as values

    and all other values is that they do something as functions other than

    "push self on stack".  So you can't just say its name to get the 'first'

    symbol on the stack; instead, you must use a circumlocution such as

    '"first" intern' or '[first] first' instead.

    Furthermore, by what I consider a bug in Joy, second-order functions

    will only handle lists of symbols rather than single symbols, so you

    cannot say "[1 2 3] "first" intern i" to get 1 on the stack.

    --

    John Cowan    http://ccil.org/~cowan    cowan@...

    Mr. Henry James writes fiction as if it were a painful duty.  --Oscar Wilde

## John Cowan — 2009-02-27 05:10:46

    Adam scripsit:

     > Are you aware of the word execute

    > (http://docs.factorcode.org/content/word-execute,words.html)?

     I don't know the details of Factor, only of Joy.

    --

    John Cowan   cowan@...   http://ccil.org/~cowan

    I must confess that I have very little notion of what [s. 4 of the British

    Trade Marks Act, 1938] is intended to convey, and particularly the sentence

    of 253 words, as I make them, which constitutes sub-section 1.  I doubt if

    the entire statute book could be successfully searched for a sentence of

    equal length which is of more fuliginous obscurity. --MacKinnon LJ, 1940

## John Nowak — 2009-02-27 12:31:24

    On Feb 26, 2009, at 7:02 PM, zallambo wrote:

     > William Tanksley wrote:

    >

    >> Stevan Apter wrote:

    >>

    >>> John Nowak wrote:

    >>>

    >>>> What XY does seems even worse though! Here's why:

    >>>>   1. [dup] i == [dup] first i  (given, as per your example)

    >>>>   2. [dup] == [dup] first      (removing shared 'i' suffix)

    >>>>   3. id == first               (removing share '[dup]' prefix)

    >>>

    >>> no.  dup = [dup] first.

    >>

    >> You're right, but he's also right -- you should always be able to

    >> remove

    >> identical suffixes from both sides of the equation, and in this

    >> case you

    >> can't do that.

    >

    > (2) does not follow from (1) and (3) does not follow from (2).

     You're right. You can add prefixes/suffixes but not necessarily remove

    them. I got my wires crossed somewhere along the way. My apologies.

     > I think John has a point though. We need a way to distinguish between

    > the function 'dup' and the object 'dup'. I suggest putting a single

    > quote in front of objects, like symbols in Scheme. So

    >

    > [dup] i == dup

    > [dup] first == 'dup

     I think we need to be careful here. If we intend both sides of the

    equality to be a function, then 'dup cannot be an object.

     > Does anyone have another syntax for writing 'dup? I cannot recall

    > seeing any.

     In the initial email, I proposed using `dup to indicate the constant

    function that returns dup. This would allow you to state the following:

        [dup] first == `dup

    It's important to note that '[dup] != `dup'. I proposed getting rid of

    quotation to solve this issue. It obviously would be a big change for

    Joy and XY. For something like Cat, it would be minor.

    - John

## John Nowak — 2009-02-27 12:33:06

    On Feb 26, 2009, at 9:58 PM, Adam wrote:

     > Are you aware of the word execute

    > (http://docs.factorcode.org/content/word-execute,words.html)?

     Yes.

     > If I understand Chris, the current call/execute distinction reveals

    > your

    > problem but I'm not sure.

     More the other way around. I think it's important to treat the object

    [dup] and the object dup differently.

    - John

## John Nowak — 2009-02-27 12:36:57

    On Feb 27, 2009, at 12:05 AM, John Cowan wrote:

     > Furthermore, by what I consider a bug in Joy, second-order functions

    > will only handle lists of symbols rather than single symbols, so you

    > cannot say "[1 2 3] "first" intern i" to get 1 on the stack.

     I don't consider this a bug. The rule for 'i' is as follows:

        [F] i -> F

    Changing 'i' to also operate on symbols would complicate things.

    Perhaps it's a tradeoff.

    - John

## Stevan Apter — 2009-02-27 13:24:57

    in f, which is modelled on the 'false' language, i distinguish

    primitives like + and defined words like 'dup'.

    dup is defined as the shuffle 'a-aa, where ' is syntactic quotation.

    a primitive executes immediately, a defined word pushes its definition

    onto the stack.  ! (i) moves the top of the stack to the head of the

    queue.

    so e.g. we have

    G>dup

    'a-aa

    G>2

    'a-aa 2

    G>swap

    'a-aa 2 'ab-ba

    G>!

    2 'a-aa

    G>!

    2 2

    G>

    and

    G>[dup swap]first

    [dup swap] [uncons ! pop !]

    G>!

    dup

    G>!

    'a-aa

    G>

    a primitive is identical to its definition:

    G>2 3 [+]first!

    2 3 +

    G>!

    5

    G>

    www.nsl.com/k/f/f.htm

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Friday, February 27, 2009 7:36 AM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    > On Feb 27, 2009, at 12:05 AM, John Cowan wrote:

    >

    >> Furthermore, by what I consider a bug in Joy, second-order functions

    >> will only handle lists of symbols rather than single symbols, so you

    >> cannot say "[1 2 3] "first" intern i" to get 1 on the stack.

    >

    > I don't consider this a bug. The rule for 'i' is as follows:

    >

    >    [F] i -> F

    >

    > Changing 'i' to also operate on symbols would complicate things.

    > Perhaps it's a tradeoff.

    >

    > - John

    >

    >

## William Tanksley — 2009-02-27 16:52:10

    John Nowak wrote:

     > More the other way around. I think it's important to treat the object

    > [dup] and the object dup differently.

     Why? In what way are they different? Won't they do the same thing when

    executed? Is there any function that should return a different result

    when called on one than another?

     > - John

     -Wm

## John Nowak — 2009-02-27 18:13:27

    On Feb 27, 2009, at 11:52 AM, William Tanksley wrote:

     > John Nowak wrote:

    >

    >> More the other way around. I think it's important to treat the object

    >> [dup] and the object dup differently.

    >

    > Why? In what way are they different?

     I'll be using Joy for all of these examples.

    dup and [dup] are not the same object. I'd hope you'd agree that this

    holds:

        [dup]  !=  [dup] first

    If the above functions produced the same object, then this would be

    true:

        [dup] first  ==  [dup] first first

    And obviously it is not; the right side will cause an error.

     > Is there any function that should return a different result when

    > called on one than another?

     Sure. Calling 'quote' on the object dup should yield the object [dup].

    Calling it on the object [dup] should yield the object [[dup]]. I'm

    sure you'd agree that [dup] and [[dup]] are not the same object, and

    hence it follows that dup and [dup] are not the same object.

    The whole problem is that, in my opinion, "open" quotations suck. For

    example, this rule always holds true in Cat:

        quote i == id  (note: Cat renames 'i' to 'apply')

    However, this does not hold in Joy. Here's an example of why taken

    straight from the Joy REPL (where 'quote' is defined as '[] cons'):

        5 [dup] first stack .

        [dup 5]

        5 [dup] first quote i stack .

        [5 5]

    If you were to disallow open quotations, the 'quote i == id' rule

    would hold in Joy.

    That's not really the main reason open quotations suck; the real

    problems are:

    1. You can no longer factor code indiscriminately.

    2. You have these ugly naked function objects to deal with!

    Forgive me for continuing to make this same point. It is the cause of

    this naked function dilemma however, so I can't really avoid

    mentioning it.

    - John

## William Tanksley — 2009-02-27 18:29:31

    John Nowak wrote:

     > William Tanksley wrote:

    > > John Nowak wrote:

    > >> More the other way around. I think it's important to treat the object

    > >> [dup] and the object dup differently.

    > > Why? In what way are they different?

    > I'll be using Joy for all of these examples.

    > The whole problem is that, in my opinion, "open" quotations suck. For

    > example, this rule always holds true in Cat:

     So you want to treat them differently because treating them differently

    sucks? :-)

    Yes, I agree that open quotations are a problem. If you don't have them,

    [dup] and `dup are equivalent by any test.

     > That's not really the main reason open quotations suck; the real

    > problems are:

    > 1. You can no longer factor code indiscriminately.

    > 2. You have these ugly naked function objects to deal with!

     Quotations, whether open or closed, ARE "naked function objects".

     > - John

     -Wm

## Stevan Apter — 2009-02-27 18:46:46

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

    From: "William Tanksley" <wtanksleyjr@...>

    To: <concatenative@yahoogroups.com>

    Sent: Friday, February 27, 2009 1:29 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    > John Nowak wrote:

    >> William Tanksley wrote:

    >> > John Nowak wrote:

    >> >> More the other way around. I think it's important to treat the object

    >> >> [dup] and the object dup differently.

    >> > Why? In what way are they different?

    >

    >> I'll be using Joy for all of these examples.

    >

    >> The whole problem is that, in my opinion, "open" quotations suck. For

    >> example, this rule always holds true in Cat:

    >

    > So you want to treat them differently because treating them differently

    > sucks? :-)

    >

    > Yes, I agree that open quotations are a problem. If you don't have them,

    > [dup] and `dup are equivalent by any test.

    >

    >> That's not really the main reason open quotations suck; the real

    >> problems are:

    >> 1. You can no longer factor code indiscriminately.

    i don't want to spoil the party, but the fact is, i'm rarely in

    the position where i *want* to factor my code.  my building blocks

    are not words or code-fragments, they're *functions*.  typically,

    a function evolves over time in response to demands from the

    environment by acquiring new arguments and/or producing results

    with new components.  the large-scale "topography" of the system

    is relatively stable.  (come to think of it, this is a pretty

    good metaphor for how systems grow in the real world.)  if i have

    to dig into the functions and move snippets of code around into

    a new functional architecture, then my original design was pitched

    at the wrong "level."  the kind of refactoring i want to avoid

    (because it is the most painful kind) is *renaming*.  going from

    a set of several hundred functions a,b,c,... to a different set

    x,y,z,... .  code is committed to a function with a name when

    a judgement is made that that functionality will endure for the

    lifetime of the system, and that changes will for the most part

    be extensions rather than revisions.

    >> 2. You have these ugly naked function objects to deal with!

    i guess i don't see the problem here.  f, [f], [[f]], ...  seems

    quite intuitive to me.

    >

    > Quotations, whether open or closed, ARE "naked function objects".

    >

    >> - John

    >

    > -Wm

    >

    >

    >

## Stevan Apter — 2009-02-27 18:56:38

    at this point i'd just like to reflect on the cost one pays

    for designing a language which tries to (i'm not sure how to

    say this) maximize refactorability.  i'm tempted to say that

    such a language will send the programmer down a path where

    refactoring is more often required, even in cases where the

    necessary changes are trivial.  this is probably not a good

    thing.  to give the first reason that occurs to me:  refactoring

    (and i've done a fair bit of it in developing examples for

    the various concatenative languages i've written over the

    years) seems to me to be inherently error-prone, more so than

    adding new arguments to functions or modifying what they

    return.  now it may be that most of the problems i've encountered

    in refactoring exercises are due to the fact that my languages

    use "open quotation," but if so, that isn't immediately obvious

    to me.

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

    From: "Stevan Apter" <sa@...>

    To: <concatenative@yahoogroups.com>

    Sent: Friday, February 27, 2009 1:46 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

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

    > From: "William Tanksley" <wtanksleyjr@...>

    > To: <concatenative@yahoogroups.com>

    > Sent: Friday, February 27, 2009 1:29 PM

    > Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    >

    >> John Nowak wrote:

    >>> William Tanksley wrote:

    >>> > John Nowak wrote:

    >>> >> More the other way around. I think it's important to treat the object

    >>> >> [dup] and the object dup differently.

    >>> > Why? In what way are they different?

    >>

    >>> I'll be using Joy for all of these examples.

    >>

    >>> The whole problem is that, in my opinion, "open" quotations suck. For

    >>> example, this rule always holds true in Cat:

    >>

    >> So you want to treat them differently because treating them differently

    >> sucks? :-)

    >>

    >> Yes, I agree that open quotations are a problem. If you don't have them,

    >> [dup] and `dup are equivalent by any test.

    >>

    >>> That's not really the main reason open quotations suck; the real

    >>> problems are:

    >>> 1. You can no longer factor code indiscriminately.

    >

    > i don't want to spoil the party, but the fact is, i'm rarely in

    > the position where i *want* to factor my code.  my building blocks

    > are not words or code-fragments, they're *functions*.  typically,

    > a function evolves over time in response to demands from the

    > environment by acquiring new arguments and/or producing results

    > with new components.  the large-scale "topography" of the system

    > is relatively stable.  (come to think of it, this is a pretty

    > good metaphor for how systems grow in the real world.)  if i have

    > to dig into the functions and move snippets of code around into

    > a new functional architecture, then my original design was pitched

    > at the wrong "level."  the kind of refactoring i want to avoid

    > (because it is the most painful kind) is *renaming*.  going from

    > a set of several hundred functions a,b,c,... to a different set

    > x,y,z,... .  code is committed to a function with a name when

    > a judgement is made that that functionality will endure for the

    > lifetime of the system, and that changes will for the most part

    > be extensions rather than revisions.

    >

    >>> 2. You have these ugly naked function objects to deal with!

    >

    > i guess i don't see the problem here.  f, [f], [[f]], ...  seems

    > quite intuitive to me.

    >

    >>

    >> Quotations, whether open or closed, ARE "naked function objects".

    >>

    >>> - John

    >>

    >> -Wm

    >>

    >>

    >>

    >

## John Nowak — 2009-02-27 18:56:38

    On Feb 27, 2009, at 1:29 PM, William Tanksley wrote:

     >> The whole problem is that, in my opinion, "open" quotations suck. For

    >> example, this rule always holds true in Cat:

    >

    > So you want to treat them differently because treating them

    > differently

    > sucks? :-)

     It's more that I want to be consistent in treating them differently

    since we *must* treat them differently once we have open quotations.

    In Joy, no function treats them similarly that I know of. In XY, only

    'i' seems to treat them similarly. I think this exception is a mistake.

     > Yes, I agree that open quotations are a problem. If you don't have

    > them,

    > [dup] and `dup are equivalent by any test.

     My main point though is that, without open quotations, you never need

    to see the object dup on the stack in the first place! It avoids the

    entire issue. Cat is a good example of how this can work.

     > Quotations, whether open or closed, ARE "naked function objects".

     By naked function objects, I specifically meant functions not in a

    quotation. They cause the problem that '[dup] first' looks like it

    would return 'dup', but '[dup] first' is not the same function as

    'dup'. This causes problems when manipulating programs and is

    precisely what I was trying to address in my initial email. Zallambo

    has understood my point, but I think his solution of using (') to

    denote an object is unsatisfactory because objects cannot be composed

    and something like "'dup 42" looks like a function composition.

    - John

## John Nowak — 2009-02-27 19:03:22

    On Feb 27, 2009, at 1:46 PM, Stevan Apter wrote:

     > i guess i don't see the problem here.  f, [f], [[f]], ...  seems

    > quite intuitive to me.

     Last try. Please don't take the list format below as exasperation,

    condescension, or anything of the like; I just want to convince you

    I'm not nuts at this point:

    1. '[dup] first' returns the *function object* 'dup'.

    2. '[dup] first != dup' because the 'dup' on the right is a *function*

    and not a *function object* as it was in 1.

    3. I want a notation to avoid this confusion.

    4. I have proposed '[dup] first == `dup', where '`dup' is a *function*

    that pushes the *function object* 'dup' onto the stack.

    5. '`dup' must be a *function*, not a *function object*, because all

    terms in a concatenative language denote functions; if they weren't

    functions, you couldn't concatenate them to compose them.

    - John

## John Nowak — 2009-02-27 19:05:39

    On Feb 27, 2009, at 1:56 PM, Stevan Apter wrote:

     > at this point i'd just like to reflect on the cost one pays

    > for designing a language which tries to (i'm not sure how to

    > say this) maximize refactorability.  i'm tempted to say that

    > such a language will send the programmer down a path where

    > refactoring is more often required, even in cases where the

    > necessary changes are trivial.

     I think you're absolutely right. Forth and friends *demand* short

    words, and consequently, demand factoring. A language like Scheme

    makes it harder to factor, but the nesting and locals means much

    larger definitions are readable, and consequently, much less factoring

    is required.

    - John

## Stevan Apter — 2009-02-27 19:37:55

    i appreciate your forebearance.  i may have a useful analogy from

    planet k.

    consider

        2+3

    we say that this expression is an nvn -- a noun-verb-noun -- which

    is a proposition about the grammar of an expression.

    in the context of expressions like 2+3 "+" is a verb.  speaking

    loosely, in the context of 2+3, "+" denotes the addition function,

    although strictly speaking, it doesn't really denote anything.

    now, when i assign a name to + as in:

        a:+

    or pass + to a function as in:

        f[+;10]

    then i say that + is a piece of data, and has the grammatical form

    of a noun.  the verb has been "nominalized."

    why a noun?  because to apply the function + i say:

        a . 10 20

      30

    which is an nvn - a noun a, a verb ., and a noun 10 20.  a is clearly

    not a verb, since i can't say

        2 a 3

    so, i would say, when you claim that

        [dup] first != dup

    you're equivocating between two contexts, one in which the function

    is a piece of data on the stack (what you call a function object), and

    one in which "dup" a term in an expression.

    in other words, this equivocation is leading you to reify a categorial

    distinction between syntax and semantics as a semantic distinction between

    two kinds of objects, functions and function-objects.  this is similar to

    the predicament k programmers get themselves into by asking why they can't

    say:

        a:+

        2 a 3

    or

        + . 2 3

    (in the first case, the grammar is nnn, in the second it's vvnn)

    in XY it's very clear that what's on the stack after [dup]first is

    evaluated, what's on the queue when dup is moved from the stack to

    to the queue by i, and what's on the stack after the user enters

    2 dup, is the very same object.  call it a function, call it a function-

    object, call it a symbol - it doesn't really matter.

    apologies if this only adds to the confusion.

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Friday, February 27, 2009 2:03 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    > On Feb 27, 2009, at 1:46 PM, Stevan Apter wrote:

    >

    >> i guess i don't see the problem here.  f, [f], [[f]], ...  seems

    >> quite intuitive to me.

    >

    > Last try. Please don't take the list format below as exasperation,

    > condescension, or anything of the like; I just want to convince you

    > I'm not nuts at this point:

    >

    > 1. '[dup] first' returns the *function object* 'dup'.

    > 2. '[dup] first != dup' because the 'dup' on the right is a *function*

    > and not a *function object* as it was in 1.

    > 3. I want a notation to avoid this confusion.

    > 4. I have proposed '[dup] first == `dup', where '`dup' is a *function*

    > that pushes the *function object* 'dup' onto the stack.

    > 5. '`dup' must be a *function*, not a *function object*, because all

    > terms in a concatenative language denote functions; if they weren't

    > functions, you couldn't concatenate them to compose them.

    >

    > - John

    >

## John Nowak — 2009-02-27 21:13:37

    On Feb 27, 2009, at 2:37 PM, Stevan Apter wrote:

     > i appreciate your forebearance.  i may have a useful analogy from

    > planet k.

     Thanks, that does make sense. Maybe I can put it in those terms.

    Take this expression:

        2 [dup] first

    Here, '2' is a verb. So are '[dup]' and 'first'. Indeed, everything is

    a verb in a concatenative *program* (very careful emphasis on

    "program" there) because all terms denote functions.

    The problem occurs when you *reduce* the program. Let's go step by step:

        2 [dup] first     (initial state)

        2 [dup] first     (after evaluating the function '2')

        2 [dup] first     (after evaluating the function '[dup]')

        2 dup             (after evaluating the function 'first')

    The end of this evaluation is '2 dup'. The important thing here though

    is now '2' and 'dup' are nouns. You cannot further reduce '2 dup' to

    '2 2' even though the syntax makes it look like you should be able to.

    It's this syntactic confusion I want to address. I want to be able to

    do reductions like I did above--that is, without keeping an explicit

    stack--while making it clear which things are verbs and which things

    are nouns.

    To reiterate, nouns do not occur in the programs you write, but they

    *do* occur when reducing those programs.

    One way to solve this problem is to use some symbol, perhaps a quote

    as zallambo suggested, to indicate which things are nouns. Using this

    technique, we can do our reduction again:

        2 [dup] first     (initial state)

        '2 [dup] first    (after evaluating the function '2')

        '2 '[dup] first   (after evaluating the function '[dup]')

        '2 'dup           (after evaluating the function 'first')

    In this case, we end up with "'2 'dup". It's clear from looking at the

    expression that we're done reducing the program. It avoids the

    confusion of looking at '2 dup' and not being sure if we're supposed

    to do reduce it to '2 2' or not.

    (Hopefully the issue I want to address is clear now. It may get fuzzy

    from this point on...)

    Unfortunately, I take issue with zallambo's proposal. My problem with

    it--if I understand it correctly--is that it creates two languages,

    one for writing programs and another to use when reducing them.

    Perhaps I'm being overly pedantic, but he said 'foo denotes an

    *object*, and objects are not part of the term language when writing a

    program. "All terms denote functions."

    My proposal differs from zallambo's in that I prefer to add a "push"

    functional form to the language itself so that you do not have a two

    syntaxes. Instead, you use the same syntax for writing a program and

    for reducing a program.

    The "push" form would be written with a back-tick and would indicate a

    function that pushes itself onto the stack; essentially, it self-

    evaluates like a quoted expression does in Scheme. Also as in Scheme,

    it would not be necessary to quote things which always evaluate to

    themselves (like numbers); only things that don't (namely functions).

    To make this model compatible with open quotations, quotation would

    apply "push" to every *noun* within it to lift them to verbs. For

    example, the following would be equivalent:

        `foo `bar [] cons cons

        [foo bar]

    Here's the same reduction again with my proposal:

        2 [dup] first     (initial state)

        2 [dup] first     (after evaluating the function '2')

        2 [dup] first     (after evaluating the function '[dup]')

        2 `dup            (after evaluating the function 'first')

    (Remember that quotation applies "push" to everything with it, so

    '`dup' really is the first element of '[dup]'.)

    This syntax has the advantages of zallambo's, but it has an important

    additional benefit; each step of the reduction is itself a valid

    program. To repeat, the syntax we use for the reduction can also be

    used for writing programs.

    - John

## Don Groves — 2009-02-27 22:22:48

    It's one thing to say that everything is a function in concatenative

    languages

    but confusion can arise if we don't distinguish between functions like

    dup,

    which manipulate objects already on the stack, and literals, whose

    function

    is to push themselves onto the stack.

    In Joy, for example, there are three kinds of literals -- numbers,

    text strings,

    and lists. The function performed by all three is to push themselves

    onto

    the stack. Once on the stack, they are no longer functions, they are

    data,

    presumably to be operated on by some function in the future.

    So, both [dup] and dup are functions but clearly have separate

    semantics.

    All languages have this problem and all handle it similarly using

    quotations.

    I don't see it as a problem the programmer has to worry about.

    Even natural languages have the concept of "use" vs. "mention." When we

    mention a word in writing, we put quotes around it to call attention

    to the

    fact that this particular word is not to parsed in the usual manner

    (as in the

    previous sentence). We even do this when speaking by using our fingers

    to make air quotes. When we mean to use the word in it's usual context,

    we omit the quotes.

    Does this idea clear up possible confusion in this thread? If not,

    sorry for

    the waste of bandwidth.

    --

    don

     On Feb 27, 2009, at 1:13 PM, John Nowak wrote:

    >

    > On Feb 27, 2009, at 2:37 PM, Stevan Apter wrote:

    >

    >> i appreciate your forebearance.  i may have a useful analogy from

    >> planet k.

    >

    > Thanks, that does make sense. Maybe I can put it in those terms.

    >

    > Take this expression:

    >

    >    2 [dup] first

    >

    > Here, '2' is a verb. So are '[dup]' and 'first'. Indeed, everything is

    > a verb in a concatenative *program* (very careful emphasis on

    > "program" there) because all terms denote functions.

    >

    > The problem occurs when you *reduce* the program. Let's go step by

    > step:

    >

    >    2 [dup] first     (initial state)

    >    2 [dup] first     (after evaluating the function '2')

    >    2 [dup] first     (after evaluating the function '[dup]')

    >    2 dup             (after evaluating the function 'first')

    >

    > The end of this evaluation is '2 dup'. The important thing here though

    > is now '2' and 'dup' are nouns. You cannot further reduce '2 dup' to

    > '2 2' even though the syntax makes it look like you should be able to.

    >

    > It's this syntactic confusion I want to address. I want to be able to

    > do reductions like I did above--that is, without keeping an explicit

    > stack--while making it clear which things are verbs and which things

    > are nouns.

    >

    > To reiterate, nouns do not occur in the programs you write, but they

    > *do* occur when reducing those programs.

    >

    > One way to solve this problem is to use some symbol, perhaps a quote

    > as zallambo suggested, to indicate which things are nouns. Using this

    > technique, we can do our reduction again:

    >

    >    2 [dup] first     (initial state)

    >    '2 [dup] first    (after evaluating the function '2')

    >    '2 '[dup] first   (after evaluating the function '[dup]')

    >    '2 'dup           (after evaluating the function 'first')

    >

    > In this case, we end up with "'2 'dup". It's clear from looking at the

    > expression that we're done reducing the program. It avoids the

    > confusion of looking at '2 dup' and not being sure if we're supposed

    > to do reduce it to '2 2' or not.

    >

    > (Hopefully the issue I want to address is clear now. It may get fuzzy

    > from this point on...)

    >

    > Unfortunately, I take issue with zallambo's proposal. My problem with

    > it--if I understand it correctly--is that it creates two languages,

    > one for writing programs and another to use when reducing them.

    > Perhaps I'm being overly pedantic, but he said 'foo denotes an

    > *object*, and objects are not part of the term language when writing a

    > program. "All terms denote functions."

    >

    > My proposal differs from zallambo's in that I prefer to add a "push"

    > functional form to the language itself so that you do not have a two

    > syntaxes. Instead, you use the same syntax for writing a program and

    > for reducing a program.

    >

    > The "push" form would be written with a back-tick and would indicate a

    > function that pushes itself onto the stack; essentially, it self-

    > evaluates like a quoted expression does in Scheme. Also as in Scheme,

    > it would not be necessary to quote things which always evaluate to

    > themselves (like numbers); only things that don't (namely functions).

    >

    > To make this model compatible with open quotations, quotation would

    > apply "push" to every *noun* within it to lift them to verbs. For

    > example, the following would be equivalent:

    >

    >    `foo `bar [] cons cons

    >    [foo bar]

    >

    > Here's the same reduction again with my proposal:

    >

    >    2 [dup] first     (initial state)

    >    2 [dup] first     (after evaluating the function '2')

    >    2 [dup] first     (after evaluating the function '[dup]')

    >    2 `dup            (after evaluating the function 'first')

    >

    > (Remember that quotation applies "push" to everything with it, so

    > '`dup' really is the first element of '[dup]'.)

    >

    > This syntax has the advantages of zallambo's, but it has an important

    > additional benefit; each step of the reduction is itself a valid

    > program. To repeat, the syntax we use for the reduction can also be

    > used for writing programs.

    >

    > - John

    >

    >

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

    >

    > Yahoo! Groups Links

    >

    >

    >

## Stevan Apter — 2009-02-27 23:00:36

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Friday, February 27, 2009 4:13 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    everything on the stack is a noun, everything on the queue is a verb.

    so we can rewrite your reduction, without ambiguity, as stack | queue:

              | 2 [dup] first

      2       | [dup] first

      2 [dup] | first

      2 dup   |

    but 'verb' and 'noun' are syntactic categories, not kinds of things.

    so i would again say that all occurrences of "dup" above denote the

    same thing, viz. the dup function.

    >    2 [dup] first     (initial state)

    >    2 [dup] first     (after evaluating the function '2')

    >    2 [dup] first     (after evaluating the function '[dup]')

    >    2 dup             (after evaluating

    >

    > On Feb 27, 2009, at 2:37 PM, Stevan Apter wrote:

    >

    >> i appreciate your forebearance.  i may have a useful analogy from

    >> planet k.

    >

    > Thanks, that does make sense. Maybe I can put it in those terms.

    >

    > Take this expression:

    >

    >    2 [dup] first

    >

    > Here, '2' is a verb. So are '[dup]' and 'first'. Indeed, everything is

    > a verb in a concatenative *program* (very careful emphasis on

    > "program" there) because all terms denote functions.

    >

    > The problem occurs when you *reduce* the program. Let's go step by step:

    >

    >    2 [dup] first     (initial state)

    >    2 [dup] first     (after evaluating the function '2')

    >    2 [dup] first     (after evaluating the function '[dup]')

    >    2 dup             (after evaluating the function 'first')

    >

    > The end of this evaluation is '2 dup'. The important thing here though

    > is now '2' and 'dup' are nouns. You cannot further reduce '2 dup' to

    > '2 2' even though the syntax makes it look like you should be able to.

    >

    > It's this syntactic confusion I want to address. I want to be able to

    > do reductions like I did above--that is, without keeping an explicit

    > stack--while making it clear which things are verbs and which things

    > are nouns.

    >

    > To reiterate, nouns do not occur in the programs you write, but they

    > *do* occur when reducing those programs.

    >

    > One way to solve this problem is to use some symbol, perhaps a quote

    > as zallambo suggested, to indicate which things are nouns. Using this

    > technique, we can do our reduction again:

    >

    >    2 [dup] first     (initial state)

    >    '2 [dup] first    (after evaluating the function '2')

    >    '2 '[dup] first   (after evaluating the function '[dup]')

    >    '2 'dup           (after evaluating the function 'first')

    >

    > In this case, we end up with "'2 'dup". It's clear from looking at the

    > expression that we're done reducing the program. It avoids the

    > confusion of looking at '2 dup' and not being sure if we're supposed

    > to do reduce it to '2 2' or not.

    >

    > (Hopefully the issue I want to address is clear now. It may get fuzzy

    > from this point on...)

    >

    > Unfortunately, I take issue with zallambo's proposal. My problem with

    > it--if I understand it correctly--is that it creates two languages,

    > one for writing programs and another to use when reducing them.

    > Perhaps I'm being overly pedantic, but he said 'foo denotes an

    > *object*, and objects are not part of the term language when writing a

    > program. "All terms denote functions."

    >

    > My proposal differs from zallambo's in that I prefer to add a "push"

    > functional form to the language itself so that you do not have a two

    > syntaxes. Instead, you use the same syntax for writing a program and

    > for reducing a program.

    >

    > The "push" form would be written with a back-tick and would indicate a

    > function that pushes itself onto the stack; essentially, it self-

    > evaluates like a quoted expression does in Scheme. Also as in Scheme,

    > it would not be necessary to quote things which always evaluate to

    > themselves (like numbers); only things that don't (namely functions).

    >

    > To make this model compatible with open quotations, quotation would

    > apply "push" to every *noun* within it to lift them to verbs. For

    > example, the following would be equivalent:

    >

    >    `foo `bar [] cons cons

    >    [foo bar]

    >

    > Here's the same reduction again with my proposal:

    >

    >    2 [dup] first     (initial state)

    >    2 [dup] first     (after evaluating the function '2')

    >    2 [dup] first     (after evaluating the function '[dup]')

    >    2 `dup            (after evaluating the function 'first')

    >

    > (Remember that quotation applies "push" to everything with it, so

    > '`dup' really is the first element of '[dup]'.)

    >

    > This syntax has the advantages of zallambo's, but it has an important

    > additional benefit; each step of the reduction is itself a valid

    > program. To repeat, the syntax we use for the reduction can also be

    > used for writing programs.

    >

    > - John

    >

## Stevan Apter — 2009-02-27 23:09:44

    i think what may be clouding the issue here is the very property of

    concatenative languages we like, viz. that a syntactically well-formed

    program cannot be distinguished from the contents of the stack.  but

    simply because the syntax of the program is *minimal* doesn't mean

    that it has *no* syntax.  indeed, every joy program has the syntactic

    form

            v v v v v ....

    a concatenation of verbs, and every stack has the syntactic form

            n n n n n ....

    the queue, or program, 2 dup, is not identical to the stack consisting

    of 2 dup, even though the elements of the program are identical to the

    elements on the stack.  in fact, this amgiguity, or asymmetry, is at the

    heart of the XY evaluator semantics.

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

    From: "Stevan Apter" <sa@...>

    To: <concatenative@yahoogroups.com>

    Sent: Friday, February 27, 2009 6:00 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

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

    > From: "John Nowak" <john@...>

    > To: <concatenative@yahoogroups.com>

    > Sent: Friday, February 27, 2009 4:13 PM

    > Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    >

    > everything on the stack is a noun, everything on the queue is a verb.

    > so we can rewrite your reduction, without ambiguity, as stack | queue:

    >

    >          | 2 [dup] first

    >  2       | [dup] first

    >  2 [dup] | first

    >  2 dup   |

    >

    > but 'verb' and 'noun' are syntactic categories, not kinds of things.

    > so i would again say that all occurrences of "dup" above denote the

    > same thing, viz. the dup function.

    >

    >

    >>    2 [dup] first     (initial state)

    >>    2 [dup] first     (after evaluating the function '2')

    >>    2 [dup] first     (after evaluating the function '[dup]')

    >>    2 dup             (after evaluating

    >>

    >> On Feb 27, 2009, at 2:37 PM, Stevan Apter wrote:

    >>

    >>> i appreciate your forebearance.  i may have a useful analogy from

    >>> planet k.

    >>

    >> Thanks, that does make sense. Maybe I can put it in those terms.

    >>

    >> Take this expression:

    >>

    >>    2 [dup] first

    >>

    >> Here, '2' is a verb. So are '[dup]' and 'first'. Indeed, everything is

    >> a verb in a concatenative *program* (very careful emphasis on

    >> "program" there) because all terms denote functions.

    >>

    >> The problem occurs when you *reduce* the program. Let's go step by step:

    >>

    >>    2 [dup] first     (initial state)

    >>    2 [dup] first     (after evaluating the function '2')

    >>    2 [dup] first     (after evaluating the function '[dup]')

    >>    2 dup             (after evaluating the function 'first')

    >>

    >> The end of this evaluation is '2 dup'. The important thing here though

    >> is now '2' and 'dup' are nouns. You cannot further reduce '2 dup' to

    >> '2 2' even though the syntax makes it look like you should be able to.

    >>

    >> It's this syntactic confusion I want to address. I want to be able to

    >> do reductions like I did above--that is, without keeping an explicit

    >> stack--while making it clear which things are verbs and which things

    >> are nouns.

    >>

    >> To reiterate, nouns do not occur in the programs you write, but they

    >> *do* occur when reducing those programs.

    >>

    >> One way to solve this problem is to use some symbol, perhaps a quote

    >> as zallambo suggested, to indicate which things are nouns. Using this

    >> technique, we can do our reduction again:

    >>

    >>    2 [dup] first     (initial state)

    >>    '2 [dup] first    (after evaluating the function '2')

    >>    '2 '[dup] first   (after evaluating the function '[dup]')

    >>    '2 'dup           (after evaluating the function 'first')

    >>

    >> In this case, we end up with "'2 'dup". It's clear from looking at the

    >> expression that we're done reducing the program. It avoids the

    >> confusion of looking at '2 dup' and not being sure if we're supposed

    >> to do reduce it to '2 2' or not.

    >>

    >> (Hopefully the issue I want to address is clear now. It may get fuzzy

    >> from this point on...)

    >>

    >> Unfortunately, I take issue with zallambo's proposal. My problem with

    >> it--if I understand it correctly--is that it creates two languages,

    >> one for writing programs and another to use when reducing them.

    >> Perhaps I'm being overly pedantic, but he said 'foo denotes an

    >> *object*, and objects are not part of the term language when writing a

    >> program. "All terms denote functions."

    >>

    >> My proposal differs from zallambo's in that I prefer to add a "push"

    >> functional form to the language itself so that you do not have a two

    >> syntaxes. Instead, you use the same syntax for writing a program and

    >> for reducing a program.

    >>

    >> The "push" form would be written with a back-tick and would indicate a

    >> function that pushes itself onto the stack; essentially, it self-

    >> evaluates like a quoted expression does in Scheme. Also as in Scheme,

    >> it would not be necessary to quote things which always evaluate to

    >> themselves (like numbers); only things that don't (namely functions).

    >>

    >> To make this model compatible with open quotations, quotation would

    >> apply "push" to every *noun* within it to lift them to verbs. For

    >> example, the following would be equivalent:

    >>

    >>    `foo `bar [] cons cons

    >>    [foo bar]

    >>

    >> Here's the same reduction again with my proposal:

    >>

    >>    2 [dup] first     (initial state)

    >>    2 [dup] first     (after evaluating the function '2')

    >>    2 [dup] first     (after evaluating the function '[dup]')

    >>    2 `dup            (after evaluating the function 'first')

    >>

    >> (Remember that quotation applies "push" to everything with it, so

    >> '`dup' really is the first element of '[dup]'.)

    >>

    >> This syntax has the advantages of zallambo's, but it has an important

    >> additional benefit; each step of the reduction is itself a valid

    >> program. To repeat, the syntax we use for the reduction can also be

    >> used for writing programs.

    >>

    >> - John

    >>

    >

## John Nowak — 2009-02-28 00:03:07

    On Feb 27, 2009, at 6:00 PM, Stevan Apter wrote:

     > everything on the stack is a noun, everything on the queue is a verb.

    > so we can rewrite your reduction, without ambiguity, as stack | queue:

    >

    >          | 2 [dup] first

    >  2       | [dup] first

    >  2 [dup] | first

    >  2 dup   |

     Indeed you can. Or you can rewrite it without ambiguity using an

    explicit stack.

    The trouble is that both approaches make it impossible to reduce in an

    arbitrary order and at arbitrary levels. For example, I'd like to be

    able to do the following:

        1 2 3 + [[dup] first] [swap] first 5 2 +

        1 2 3 + [`dup] [swap] first 5 2 +

        1 2 3 + [`dup] [swap] first 7

        1 2 3 + [`dup] `swap 7

        1 5 [`dup] `swap 7

    This is not possible if you use an explicit stack/queue for your

    reduction. You need to make sure each step in the reduction is itself

    a valid program.

    - John

## Stevan Apter — 2009-02-28 13:21:22

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Friday, February 27, 2009 7:03 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    > On Feb 27, 2009, at 6:00 PM, Stevan Apter wrote:

    >

    >> everything on the stack is a noun, everything on the queue is a verb.

    >> so we can rewrite your reduction, without ambiguity, as stack | queue:

    >>

    >>          | 2 [dup] first

    >>  2       | [dup] first

    >>  2 [dup] | first

    >>  2 dup   |

    >

    > Indeed you can. Or you can rewrite it without ambiguity using an

    > explicit stack.

    >

    > The trouble is that both approaches make it impossible to reduce in an

    > arbitrary order and at arbitrary levels. For example, I'd like to be

    > able to do the following:

    >

    >    1 2 3 + [[dup] first] [swap] first 5 2 +

    >    1 2 3 + [`dup] [swap] first 5 2 +

    >    1 2 3 + [`dup] [swap] first 7

    >    1 2 3 + [`dup] `swap 7

    >    1 5 [`dup] `swap 7

    >

    > This is not possible if you use an explicit stack/queue for your

    > reduction. You need to make sure each step in the reduction is itself

    > a valid program.

    sure.  but `dup is just notation.  it's a method of recording that dup

    has changed its role in the reduction.

    >

    > - John

    >

## John Nowak — 2009-02-28 16:04:30

    On Feb 28, 2009, at 8:21 AM, Stevan Apter wrote:

     >> The trouble is that both approaches make it impossible to reduce in

    >> an

    >> arbitrary order and at arbitrary levels. For example, I'd like to be

    >> able to do the following:

    >>

    >>   1 2 3 + [[dup] first] [swap] first 5 2 +

    >>   1 2 3 + [`dup] [swap] first 5 2 +

    >>   1 2 3 + [`dup] [swap] first 7

    >>   1 2 3 + [`dup] `swap 7

    >>   1 5 [`dup] `swap 7

    >

    > sure.  but `dup is just notation.  it's a method of recording that dup

    > has changed its role in the reduction.

     *explodes*

    The whole point is that dup would not just serve that role! You could

    write `dup and it would be a valid program or you could write `(dup

    swap) and it would be a valid program. See my original email and this

    comment in my other response to you:

     > Unfortunately, I take issue with zallambo's proposal. My problem with

    > it--if I understand it correctly--is that it creates two languages,

    > one for writing programs and another to use when reducing them.

    > Perhaps I'm being overly pedantic, but he said 'foo denotes an

    > *object*, and objects are not part of the term language when writing a

    > program. "All terms denote functions."

    > ...

    > This syntax has the advantages of zallambo's, but it has an important

    > additional benefit; each step of the reduction is itself a valid

    > program. To repeat, the syntax we use for the reduction can also be

    > used for writing programs.

     I don't see how I can be more clear. Perhaps you've just lost interest

    awhile back. I know I have.

    Time for my morning coffee...

    - John

## William Tanksley — 2009-03-02 18:36:35

    Stevan Apter wrote:

     > i don't want to spoil the party, but the fact is, i'm rarely in

    > the position where i *want* to factor my code.

     Yeah, well, you're a party-spoiler anyhow. :-)

     >  my building blocks

    > are not words or code-fragments, they're *functions*.

     I do not understand this. "Word" is the Forth term for what other

    languages call "functions". And most of what other languages call

    "functions" are built of code-fragments.

    Being able to put together and take apart functions/words is pretty

    useful to programming. That's what the functional programming mavens

    talk about with their "referential transparency"... and concatenative

    languages are a bit better at that.

    In brief, I don't understand why you'd "complain" about being _able_ to

    refactor code more easily. I understand that you want to analyse

    requirements, architect solutions, and detail-design perfectly the first

    time... But since none of these are possible, it makes sense to write

    code that's as mutable as possible.

     > typically,

    > a function evolves over time in response to demands from the

    > environment by acquiring new arguments and/or producing results

    > with new components.  the large-scale "topography" of the system

    > is relatively stable.

    > (come to think of it, this is a pretty

    > good metaphor for how systems grow in the real world.)

     Good for you -- I'm not so lucky. For me there are two ways that a

    system changes: either we fix problems in the code that implemented the

    old requirements, or new requirements get added. In both cases the

    architecture usually has to change at least a bit.

     > if i have

    > to dig into the functions and move snippets of code around into

    > a new functional architecture, then my original design was pitched

    > at the wrong "level."

     It probably _was_ pitched at the wrong level. This happens all the time.

     > the kind of refactoring i want to avoid

    > (because it is the most painful kind) is *renaming*.  going from

    > a set of several hundred functions a,b,c,... to a different set

    > x,y,z,... .

     I would classify renaming as the simplest kind of refactoring -- it can

    usually be done with a simple search and replace, and then let the

    compiler tell you if you missed anything. I wouldn't make a million name

    changes at the same time, of course.

     > code is committed to a function with a name when

    > a judgement is made that that functionality will endure for the

    > lifetime of the system, and that changes will for the most part

    > be extensions rather than revisions.

     I expect that from code that's been in production use for 10 years.

    Nothing younger.

    -Wm

## William Tanksley — 2009-03-02 18:44:41

    John Nowak wrote:

     > I think you're absolutely right. Forth and friends *demand* short

    > words, and consequently, demand factoring.A language like Scheme

    > makes it harder to factor, but the nesting and locals means much

    > larger definitions are readable, and consequently, much less factoring

    > is required.

     There's truth in what you're saying, but you're missing an important

    fact: short definitions are easier to read in _any_ language. I admit

    that it's important to be able to express longer words.

    I do agree that Forth is a system language, with poor facilities for any

    higher-level work. I don't concede anything :-) about "Forth and

    friends", since I don't know what languages you're refering to.

    It's good to be free from the restrictions of Forth. It's also good to

    keep the benefits Forth has historically enjoyed, one of which is easy

    refactoring.

    Factor's EMACS mode, "Fuel", supports automated refactoring.

     > - John

     -Wm

## John Nowak — 2009-03-02 20:55:38

    On Mar 2, 2009, at 1:44 PM, William Tanksley wrote:

     > John Nowak wrote:

    >

    >> I think you're absolutely right. Forth and friends *demand* short

    >> words, and consequently, demand factoring.A language like Scheme

    >> makes it harder to factor, but the nesting and locals means much

    >> larger definitions are readable, and consequently, much less

    >> factoring

    >> is required.

    >

    > There's truth in what you're saying, but you're missing an important

    > fact: short definitions are easier to read in _any_ language. I admit

    > that it's important to be able to express longer words.

     You're right; I didn't mean to imply otherwise. Ideally, a language

    should make writing long definitions possible (which I often find

    useful in Scheme when prototyping and experimenting) and short

    definitions elegant (which concatenative languages do well). I don't

    know of a language that satisfies both of these criteria to the degree

    I'd like, although some do come fairly close.

     > I do agree that Forth is a system language, with poor facilities for

    > any

    > higher-level work. I don't concede anything :-) about "Forth and

    > friends", since I don't know what languages you're refering to.

     I was referring to stack-based languages in general; the average

    length of a function definition needs to be shorter than in a language

    like Scheme to achieve the same level of readability. The nesting in

    Scheme helps visually and things remain mostly understandable even if

    you don't know the arities of all the functions involved. That's only

    my opinion of course; I've not launched a study to determine if this

    goes for most people, although I suspect it does.

     > Factor's EMACS mode, "Fuel", supports automated refactoring.

     Aye, something like this likely helps by reducing the incentive to

    write large definitions in the first place. It's a shame I've never

    managed to convince myself to learn Emacs.

    - John

## William Tanksley — 2009-03-03 17:06:49

    John Nowak wrote:

     > Ideally, a language

    > should make writing long definitions possible (which I often find

    > useful in Scheme when prototyping and experimenting) and short

    > definitions elegant (which concatenative languages do well).

     That's certainly true. A long definition that's in a considerable state

    of flux _can_ be rather hard to juggle around in a concatenative

    language. That's one time when I'd personally forgive the use of local

    variables :-), although I'd rather see the programmer spend some time

    back at the drawing board (or experimenting with primitives) first.

    Let's face it: if you don't know what you're doing yet, you're picking a

    poor time to commit to code. The overhead of stack manipulations is only

    a part of the problem you're going to face.

    I admit that I've done a decent amount of exploratory programming in

    concatenative languages; and I don't think they're any more unpleasant

    in practice (although clearly in theory they're worse). You WILL wind up

    with some nasty stack shuffles, but I think that's part of the penalty

    of exploratory programming (leftover and/or misnamed temporary variables

    are essentially the same thing). If you're careful to think at every

    step you'll minimize the shuffling, and often by the end you'll

    understand the problem well enough to do a complete rewrite _correctly_.

     > > I do agree that Forth is a system language, with poor facilities for

    > > any

    > > higher-level work. I don't concede anything :-) about "Forth and

    > > friends", since I don't know what languages you're refering to.

    > I was referring to stack-based languages in general; the average

    > length of a function definition needs to be shorter than in a language

    > like Scheme to achieve the same level of readability.

     If your only measurement is how a syntax helps you see arities, then

    applicative languages win by acclamation. But there's more to reading a

    program than knowing the arities of the functions. Concatenative

    languages can reveal or conceal a lot more about dataflow, and that can

    help (or hinder) the reading as well. Depends on what tools the language

    has, and which ones the programmer uses.

     > The nesting in

    > Scheme helps visually and things remain mostly understandable even if

    > you don't know the arities of all the functions involved. That's only

    > my opinion of course; I've not launched a study to determine if this

    > goes for most people, although I suspect it does.

     Forth is the only concatenative language we've discussed that lacks

    nesting. Why would you list "nesting" as an advantage of associative

    languages?

     > > Factor's EMACS mode, "Fuel", supports automated refactoring.

    > Aye, something like this likely helps by reducing the incentive to

    > write large definitions in the first place. It's a shame I've never

    > managed to convince myself to learn Emacs.

     Heh. I'm a vim guy myself. But after so much time waiting for a C

    refactorer, it's amusing to see one pop up for Factor so quickly. It's

    actually becoming reasonably competent.

     > - John

     -Wm

## John Nowak — 2009-03-03 19:29:07

    On Mar 3, 2009, at 12:06 PM, William Tanksley wrote:

     >> The nesting in

    >> Scheme helps visually and things remain mostly understandable even if

    >> you don't know the arities of all the functions involved. That's only

    >> my opinion of course; I've not launched a study to determine if this

    >> goes for most people, although I suspect it does.

    >

    > Forth is the only concatenative language we've discussed that lacks

    > nesting. Why would you list "nesting" as an advantage of associative

    > languages?

     I was being sloppy. I've certainly proposed "concatenative" languages

    with as much nesting as you find in Scheme.

    I really was meaning to compare idiomatic ways of writing code in

    concatenative languages. Take the following code for example:

        foo bar [baz] dip quux

    You will, in practice, get concatenative code like this. Now compare

    to what might be the applicative equivalent:

        (let ([(x y z) (foo input)]

              [(b c)   (baz y z)])

          (quux (bar x) b c))

    Here, it's clear that foo returns three values, bar only cares about

    one, baz only cares about two, bar uses the first result of foo, baz

    uses the second two, baz is independent of bar, quuz uses one result

    from bar and two from baz, etc.

    Getting all of this information out of the concatenative version isn't

    possible. Does bar use one value? Two? More? What about quux? Does baz

    depend on the result of bar? All of this is clear in the applicative

    version but not the stack-based concatenative version.

    Again, in practice, I occasionally find this difficult when writing

    code quickly to prototype something. If you don't, then I certainly

    won't call you a liar. Perhaps I just have Scheme burned into my head.

    - John

## Stevan Apter — 2009-03-03 19:57:31

    let me register some dissenting opinions here (no surprise, right?)

    these have been buzzing around in my head since billy's response to

    my "anti-factoring" post.

    i expect i'll meet with some resistance here, since i can't provide

    an overwhelmingly persuasive argument (that's why they're opinions.)

    if they spark some ideas, that's enough.

    i can say the same thing in several ways:  compared to other languages

    i know, k call-trees are smaller, there are fewer names in play, and

    a greater proportion of the tokens in a k program are primitives.  (you

    can see an example of this in the game-of-life function i posted a few

    days ago.)

    the question whether one should write long or short programs hardly

    ever arises.  a program -- a function with a name -- should represent

    "a thought".  of course, x+y is a thought, and so is x+y*z, so this

    maxim isn't precise enough to be useful.  perhaps we get into the

    habit of adjusting the way we think about problems to the language

    we're used to, and therefore thinking in ways that experience has

    taught us are "best" for that language.  probably this is true to

    some extent.

    in k, programs will call other programs, but there's not a whole lot

    of complexity at that level.  when you look inside a program, mostly

    what you see are primitives and the arguments to the program.  (i'm

    not sure this is as true in j, especially the way masters of that

    language like roger hui write code.)

    the primitives are individually powerful and they fit together in ways

    that allow for great expressiveness.  usually it's possible to express

    "a thought" -- something you can give a name to, and use and remember

    easily -- in a line or two or three.  short enough to be "surveyable",

    not so short that you need to look at calling-context to understand

    meaning.  another way of saying this is that the k programmer spends

    most of his time *in primitives*.

    i think factoring becomes useful to the programmer when the primitives

    are so weak that certain phrases, certain ways of combining them,

    appear repeatedly in different contexts.  so then you wind up abstracting

    those phrases and giving them names.  and you wind up with lots and

    lots of these things, and deep, complicated call-hierarchies.  it's

    as though you didn't have + in the language, and you find it natural

    to define different special cases of addition for different contexts.

    since we are often called upon to work with aggregates of different

    kinds -- sets, bags, lists, vectors, dictionaries, tables, &c. --

    and our primitives are for the most part scalar (again, often of

    different kinds) we wind up writing lots of code for different

    special cases.  inevitably, this will result in situations where

    subtle variations on a single idea will manifest as similar code-

    fragments, and we'll go on to factor, combine, rename, &c.  that's

    a lot of complexity to manage, and i think it arises just because

    the primitives are too weak and their combinations are insufficiently

    expressive.

    this situation simply does not arise in k, or rather, it arises much

    less frequently.  this is because certain mathematical relations

    exist between different aggregate types, and the primitives are

    designed to exploit those relations.  (e.g. the transpose of a

    dictionary of lists is a table, that is, a list of similar atomic

    dictionaries.)  so x+y works predictably (and usefully!) on all

    (conformable) aggregates.

    i've had this suspicion for quite a while -- i don't know how to prove

    it.  if you were enumerate all combinations of k primitives in 1, 2, and 3

    variables (x, y, and z), you'd find a greater density of "useful"

    and "interesting" programs in the set of combinations of length < 10.

    an example i've used before is the remarkable function {x y z x}, which

    can be used for both converging boolean selection on a table and multi-

    column table sorting.  who would have thought?  this and other examples

    had led me to think that programming k was like taking a botanical field

    trip to the amazon in search of exotic new flora.

    this is also why i think enchilada is an extremely promising language.

    robbert has designed a handful of very powerful primitives, which

    interact in ways which even he, the language designer, can't fully

    predict.  hence the different proposals over the last two years, each

    of which has made use of discoveries made in the course of solving

    problems in the previous version.  i interpret this "fruitfulness",

    where application of the language generates insights into the *set

    of primitives*, as a sign that enchilada offers a new way of thinking

    about problems.  i mean to contrast this with the way i've seen most

    languages evolve, which is to add control structures, datatypes, "OO",

    compiler technologies, &c., and to ignore the primitives.

    anyway, these are just some thoughts off the top of my head.

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

    From: "William Tanksley" <wtanksleyjr@...>

    To: <concatenative@yahoogroups.com>

    Sent: Tuesday, March 03, 2009 12:06 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    > John Nowak wrote:

    >> Ideally, a language

    >> should make writing long definitions possible (which I often find

    >> useful in Scheme when prototyping and experimenting) and short

    >> definitions elegant (which concatenative languages do well).

    >

    > That's certainly true. A long definition that's in a considerable state

    > of flux _can_ be rather hard to juggle around in a concatenative

    > language. That's one time when I'd personally forgive the use of local

    > variables :-), although I'd rather see the programmer spend some time

    > back at the drawing board (or experimenting with primitives) first.

    >

    > Let's face it: if you don't know what you're doing yet, you're picking a

    > poor time to commit to code. The overhead of stack manipulations is only

    > a part of the problem you're going to face.

    >

    > I admit that I've done a decent amount of exploratory programming in

    > concatenative languages; and I don't think they're any more unpleasant

    > in practice (although clearly in theory they're worse). You WILL wind up

    > with some nasty stack shuffles, but I think that's part of the penalty

    > of exploratory programming (leftover and/or misnamed temporary variables

    > are essentially the same thing). If you're careful to think at every

    > step you'll minimize the shuffling, and often by the end you'll

    > understand the problem well enough to do a complete rewrite _correctly_.

    >

    >> > I do agree that Forth is a system language, with poor facilities for

    >> > any

    >> > higher-level work. I don't concede anything :-) about "Forth and

    >> > friends", since I don't know what languages you're refering to.

    >

    >> I was referring to stack-based languages in general; the average

    >> length of a function definition needs to be shorter than in a language

    >> like Scheme to achieve the same level of readability.

    >

    > If your only measurement is how a syntax helps you see arities, then

    > applicative languages win by acclamation. But there's more to reading a

    > program than knowing the arities of the functions. Concatenative

    > languages can reveal or conceal a lot more about dataflow, and that can

    > help (or hinder) the reading as well. Depends on what tools the language

    > has, and which ones the programmer uses.

    >

    >> The nesting in

    >> Scheme helps visually and things remain mostly understandable even if

    >> you don't know the arities of all the functions involved. That's only

    >> my opinion of course; I've not launched a study to determine if this

    >> goes for most people, although I suspect it does.

    >

    > Forth is the only concatenative language we've discussed that lacks

    > nesting. Why would you list "nesting" as an advantage of associative

    > languages?

    >

    >> > Factor's EMACS mode, "Fuel", supports automated refactoring.

    >> Aye, something like this likely helps by reducing the incentive to

    >> write large definitions in the first place. It's a shame I've never

    >> managed to convince myself to learn Emacs.

    >

    > Heh. I'm a vim guy myself. But after so much time waiting for a C

    > refactorer, it's amusing to see one pop up for Factor so quickly. It's

    > actually becoming reasonably competent.

    >

    >> - John

    >

    > -Wm

    >

    >

    >

## John Nowak — 2009-03-03 20:30:20

    On Mar 3, 2009, at 2:57 PM, Stevan Apter wrote:

     > this situation simply does not arise in k, or rather, it arises much

    > less frequently.  this is because certain mathematical relations

    > exist between different aggregate types, and the primitives are

    > designed to exploit those relations.  (e.g. the transpose of a

    > dictionary of lists is a table, that is, a list of similar atomic

    > dictionaries.)  so x+y works predictably (and usefully!) on all

    > (conformable) aggregates.

     Is Q similar to K in this regard? Where would you suggest one look to

    get a deeper understanding of what you're talking about? I've gone

    through Q for Mortals but I don't feel like I've gotten the full

    picture.

    Also, how important to do think it is that primitives in K work on

    aggregates rather than scalars? For example, would it somehow not work

    as well if it were required to indicate that you intended to apply a

    function to each element (using some concise syntax) instead of having

    it happen "automatically"? I ask because something like this would be

    necessary for typing the sort of things you do in K, and

    unfortunately, I'm not interested if I can't type it. Boring, I know.

    - John

## Stevan Apter — 2009-03-04 00:13:21

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

    From: "John Nowak" <john@...>

    To: <concatenative@yahoogroups.com>

    Sent: Tuesday, March 03, 2009 3:30 PM

    Subject: Re: [stack] function/object ambiguity + quotation alternative

    >

    > On Mar 3, 2009, at 2:57 PM, Stevan Apter wrote:

    >

    >> this situation simply does not arise in k, or rather, it arises much

    >> less frequently.  this is because certain mathematical relations

    >> exist between different aggregate types, and the primitives are

    >> designed to exploit those relations.  (e.g. the transpose of a

    >> dictionary of lists is a table, that is, a list of similar atomic

    >> dictionaries.)  so x+y works predictably (and usefully!) on all

    >> (conformable) aggregates.

    >

    > Is Q similar to K in this regard? Where would you suggest one look to

    > get a deeper understanding of what you're talking about? I've gone

    > through Q for Mortals but I don't feel like I've gotten the full

    > picture.

    q is k with keywords for unary primitives, e.g. 'count x' in q for

    '#x' in k.  i use q, only a few people use k.  the distinction makes

    no difference for the topic at hand.

    unfortunately, i don't know what to suggest short of full immersion

    in a large-scale k project.  i suppose it's possible to contemplate

    a large set of one-liners (e.g. eugene mcdonnell's finger exercises),

    or the occasional tour de force from arthur whitney (sudoku), and

    find there some evidence for my opinions about factoring.

    >

    > Also, how important to do think it is that primitives in K work on

    > aggregates rather than scalars? For example, would it somehow not work

    > as well if it were required to indicate that you intended to apply a

    > function to each element (using some concise syntax) instead of having

    > it happen "automatically"? I ask because something like this would be

    > necessary for typing the sort of things you do in K, and

    > unfortunately, I'm not interested if I can't type it. Boring, I know.

    i don't know if it is necessary for typing.  i've heard lots of claims

    over the years that this and that are impossible in k, and of course that's

    true ... until someone actually does this and that.  can k be typed?

    if not, how close can you get to k with a typed language?  is that close

    enough?

    anyway, my goal wasn't to shift the conversation to k per se, but to

    suggest that this concern with factoring might be an artifact of certain

    types of languages rather than a universal desideratum.

    >

    > - John

    >

## William Tanksley — 2009-03-04 00:22:34

    John Nowak wrote:

     > William Tanksley wrote:

    > >> The nesting in

    > >> Scheme helps visually and things remain mostly understandable even if

    > >> you don't know the arities of all the functions involved. That's only

    > I really was meaning to compare idiomatic ways of writing code in

    > concatenative languages. Take the following code for example:

    >     foo bar [baz] dip quux

    > You will, in practice, get concatenative code like this. Now compare

    > to what might be the applicative equivalent:

    >     (let ([(x y z) (foo input)]

    >           [(b c)   (baz y z)])

    >       (quux (bar x) b c))

    > Here, it's clear that foo returns three values, bar only cares about

    > one, baz only cares about two, bar uses the first result of foo, baz

    > uses the second two, baz is independent of bar, quuz uses one result

    > from bar and two from baz, etc.

     Okay, I agree. But there's another angle to look at this.

    In many problem domains, clear and communicative names can be chosen

    rather than "foo" and "bar". If that is done (and it normally IS a goal,

    even if one sometimes honored in the breach), which code chunk "wins"?

    I'd say it's pretty simple -- the code chunk that looks like it's

    communicating in the problem domain (with one apparantly random word,

    "dip"). The applicative language may use a little of the vocabulary of

    the problem domain, but it's obscured in a tangle of parentheses that

    may document to the programmer what parameters go where, but don't mean

    much to the domain expert who should be able to check at least your

    top-level algorithm.

     > Getting all of this information out of the concatenative version isn't

    > possible. Does bar use one value? Two? More? What about quux? Does baz

    > depend on the result of bar? All of this is clear in the applicative

    > version but not the stack-based concatenative version.

     The naive assumption is that every word depends on its predecessor --

    that the order is utterly critical. This assumption won't let you down,

    but it won't give you the best performance, either (and it certainly

    won't help you analyse the code when there are bugs). To do better, you

    need a smart enough development environment to tell you the signature of

    each word -- or you flip open a glossary and look at the definitions of

    the words. It's an extra step, but it's worth it.

     > Again, in practice, I occasionally find this difficult when writing

    > code quickly to prototype something. If you don't, then I certainly

    > won't call you a liar. Perhaps I just have Scheme burned into my head.

     I think you meant "when reading code". When writing, you either remember

    or you have to look it up; the parens won't help you, because you're the

    one who's writing them. With that assumption:

    Remembering stack effects without a reference handy is not natural for

    humans. No argument. Because of that, names and parens DO give an assist

    which _is_ useful. But those are only useful for programmers in that one

    context; they're an obstruction in all other contexts, much like stack

    shuffle words are. The difference is that stack shuffle words are agreed

    to be bad, and are avoided by all; parens and variables are claimed to

    be unavoidable or even beneficial.

    They're not unavoidable (concatenative languages don't need 'em), and

    although they are beneficial in some circumstances, they aren't in all.

    Of course, the ideal solution isn't permanent syntax; it's a tool that

    underlays the code with syntactic cues.

     > - John

     -Wm

## John Nowak — 2009-03-04 00:51:49

    On Mar 3, 2009, at 7:13 PM, Stevan Apter wrote:

     > i don't know if it is necessary for typing.  i've heard lots of claims

    > over the years that this and that are impossible in k, and of course

    > that's

    > true ... until someone actually does this and that.  can k be typed?

    > if not, how close can you get to k with a typed language?  is that

    > close

    > enough?

     I realize those are rhetorical questions, but...

    The language prototype I'm working on now does take some vague

    inspiration from Q. For example, you can define a 'map' function named

    (') as such:

       ' = -x(n,x.{F,'F})

    In the above definition, '-x' is a combining form that takes two

    functions. The first says what to do if the list passed to it is null

    (return null), and the second says what to do if passed a cons (apply

    some function F to the head, apply 'F to the tail, then cons the

    result).

    You can use the map function as such:

       'sq.[1,2,3,4,5]   # [1,4,9,16,15]

    Another example would be fold:

       / = +x(i,/F.[c,F.t2])

    Here, '+x' is like '-x' except it takes additional values that are

    passed to both functions. The first argument to '+x' returns the

    additional values ('i' is identity) and the second folds some function

    F over tail of the list and F applied to the accumulated value and

    head of the list.

    An example:

       /+.[[1,2,3,4,5],0]   # 15

    Alright, it's not that much like Q. For one, it works on cons cells

    instead of arrays. It does have a nice advantage though: It's

    statically typed.

    Just a little brain dump...

    - John

## John Nowak — 2009-03-04 01:02:09

    On Mar 3, 2009, at 7:51 PM, John Nowak wrote:

     >   ' = -x(n,x.{F,'F})

    >    / = +x(i,/F.[c,F.t2])

     I forgot to post them with the alternate infix syntax which is kind of

    cute. I'll give a better explanation as well.

    'a b c d e' groups to 'a b (c d e)' and is basically another way of

    writing the construction form (this is a lot like J); '.' is

    composition if that wasn't obvious; 'c' selects the third element in a

    list ('a' is the first, 'b' is second, etc); 't2' takes the first two

    elements of the list passed to it; 'x' is cons; {} is "spread":

        ' = n -x x.{F,'F}

        / = i +x c /F F.t2

    I think they're a lot better than the equivalent definitions in Joy or

    Factor. Certainly less unrelated words needed.

    - John

## William Tanksley — 2009-03-04 22:03:41

    John Nowak wrote:

     > I've hinted at this recently, but never properly explained it. It may

    > be entirely uninteresting or even an incorrect observation, so I'd

    > appreciate a whack on the hand if I'm off track. I think, however,

    > that it may be important in letting us further develop a firm

    > theoretical basis for concatenative languages.

     I think you're dead-on, and your solution is something that I've

    suggested in the past. However, I also admire the ambiguity between

    functions and literals that you first described to us, so I'd like to

    also think of a solution that might save it.

    I'm not sure that I've succeeded, but I need to send this someday.

     > This seem to be a unique property. I have never seen a non-

    > concatenative language in which every term denoted a function.

     Agreed.

     > With concatenative languages, we always use the second form for

    > expressing the semantics of some function, e.g. 'X dup == X X'. We do

    > this because we have no syntax for application and no way of

    > expressing objects. There's something strange here though. Because all

    > terms denote functions, 'X' must be a function. However, 'X' cannot be

    > any function; it must be a function that pushes a value (and always

    > the same value) onto a stack.

     Yes. This is why Kerby always places his stack variable notations in

    brackets:

      [X] dup == [X] [X]

    I've often suggested adding a notation to quote only a single symbol

    (without enclosing it in a list). You follow this approach below.

     > I believe I know how to solve this problem: Get rid of the function/

    > object ambiguity.

     I see your point.

    The problem is, we both like the function/object ambiguity. (x) denotes

    a function or an object, no real difference except that the object

    always changes the stack in the exact same way -- so the object is like

    a function.

     > To do this, we drop the requirement that all terms denote functions.

    > '42' will now denote the *number* 42. To push 42 onto the stack, we'll

    > write '`42', i.e. the push function '`' applied to the object 42.

     This is something I've proposed before. I didn't think of making it

    apply to numbers; I only wanted it for functions, because:

    [dip] first == `dip

    Making it apply to groupings is an obvious enhancement which improves

    the algebra:

    [dip dup] == `(dip dup)

    Making it apply to numbers and literals in general is needless; it'll

    work, but it should be a noop.

     > The presence of '`' allows us to get rid of quotation. Instead of '[+]

    > map', we would write '`+ map'; the '`' function applied to the '+'

    > function yields a new function that pushes the '+' function onto a

    > stack. We'd also need to add parentheses for grouping; you'd write

    > '`(foo bar)' instead of '[foo bar]'.

     I'm quite happy with this. It makes sense to be able to distinguish

    between grouping and quotation.

     > This allows us a solution to the problem with Factor's array literals

    > shown above: Array literals would only be allowed to contain terms

    > representing objects. For example, '`{ 42 `42 }' would be a function

    > that pushes an array onto a stack where the first element of the array

    > is the number 42 and the second element is a function that pushes 42

    > onto a stack.

     Yes, I think I see why this is needed. It's nice to note that (`) is

    distributive over grouping:

      `(42 `42) == (`42 ``42) == `42 ``42 compose == 42 42 compose

     > I would also suggest adding an additional array syntax that takes

    > *functions* that evaluate to single objects.

     Why only for arrays? It would make more sense to me to make a special

    group syntax that forces the evaluation of the group at the time it's

    constructed rather than the usual runtime. So an array might look like:

    { ,(2 1 drop) }

    (I'm using , because it seems like the mirror of `.)

    It's an ordinary array, with a dequoted group inside it. You can also

    make an ordinary quoted group with a dequoted group (or even a dequoted

    function) inside it, if you want.

     > In Joy, where creating multiple "copies" of the stack is cheap, you

    > could use my parallel "banana" combinator to construct lists. For

    > example, you could write the function '2 3 (|+ -|)' which would be

    > equivalent to the function '`{5 -1}' (assuming we also adopted closed

    > quotations for Joy and added '{ }' as a list literal syntax).

     I agree that this would be a great way to structure the banana

    combinator. I don't know why this would only work on Joy -- your banana

    combinator doesn't ever copy the stack, or at least it doesn't require a

    stack copy. Or perhaps I'm thinking of a slightly modified version that

    I talked about -- I forget the details now. I'd say that copying the

    stack is a really, really bad habit... or at best, a habit that there's

    no good reason for and much good reason against.

     > Since we have lost the object/function ambiguity, we can now express

    > the semantics of our functions in terms of application. I propose the

    > syntax '<object>:<function>' to indicate an application. Assuming our

    > concatenative language is stack-based, the object will always be a

    > stack.

     Wait, why couldn't this be done in the past? I don't see how this is any

    different from what we'd done before. We didn't use that specific

    notation, but we used similar notation.

     > Alternatively, we can express our semantics in terms of equivalencies.

    > This isn't as generally useful as the application form above (e.g. you

    > can't express 'clear' in this form), but it is perhaps a bit easier to

    > read:

    >     `42  ==  `42

    >     `X dup  ==  `X `X

    >     `X `Y swap  ==  `Y `X

    >     `F i  ==  F

    >     `X `F dip  ==  F `X

     Equivalencies have some nice properties of their own... A function which

    can't be thus expressed has some usability problems.

    Actually, that's kind of an interesting statement. I wonder why it seems

    true to me? Nothing about the definition of a concatenative language

    seem

     > - John

     -Wm

## John Nowak — 2009-03-04 23:04:48

    On Mar 4, 2009, at 5:03 PM, William Tanksley wrote:

     > Why only for arrays? It would make more sense to me to make a special

    > group syntax that forces the evaluation of the group at the time it's

    > constructed rather than the usual runtime. So an array might look

    > like:

    >

    > { ,(2 1 drop) }

     You're right, this is a better approach. Essentially, this would be

    the same thing as quasiquote in Scheme, and with the same syntax to

    boot. You've probably already realized this. For example, this:

        `(+ ,(+ 1 2) (+ 3 4))

    reduces to this:

        (+ 3 (+ 3 4))

     > I agree that this would be a great way to structure the banana

    > combinator. I don't know why this would only work on Joy -- your

    > banana

    > combinator doesn't ever copy the stack, or at least it doesn't

    > require a

    > stack copy.

     It does require a stack copy in a naive implementation because an

    identical stack is given to every function. Factor can typically avoid

    the stack copy thanks to its stack inference.

     > I'd say that copying the stack is a really, really bad habit... or

    > at best, a habit that there's no good reason for and much good

    > reason against.

     Copying it if it's expensive is bad; if it's cheap, it's very useful.

    In Factor, each conditional in 'cond' can alter the stack for the next

    conditional. You need to use a lot of superfluous 'dup' functions to

    avoid problems, and it removes a guarantee that you take for granted

    in most languages (provided that you're not mutating any values in

    your conditional).

    Things like this are the reason I'm not using Factor; I don't find

    that sort of thing acceptable. Maybe Factor's stack inference could be

    used to implement a 'cond' without these problems, but that's beyond

    me unfortunately. Then again, I'm not a fan of smart combinators anyway.

     >> Since we have lost the object/function ambiguity, we can now express

    >> the semantics of our functions in terms of application. I propose the

    >> syntax '<object>:<function>' to indicate an application. Assuming our

    >> concatenative language is stack-based, the object will always be a

    >> stack.

    >

    > Wait, why couldn't this be done in the past?

     My thinking was that if it's clear what is an object and what is a

    function, then we can put only objects on the left and only functions

    on the right. Without a way to represent objects, you can't really

    represent application. This is not a problem in practice; Factor

    certainly has a REPL that shows a stack with objects on it. I just

    wanted to make things a bit more clear.

    - John

## William Tanksley — 2009-03-05 18:03:13

    John Nowak wrote:

     > William Tanksley wrote:

    > > I agree that this would be a great way to structure the banana

    > > combinator. I don't know why this would only work on Joy -- your

    > > banana

    > > combinator doesn't ever copy the stack, or at least it doesn't

    > > require a stack copy.

    > It does require a stack copy in a naive implementation because an

    > identical stack is given to every function. Factor can typically avoid

    > the stack copy thanks to its stack inference.

     I'd simply not perform the stack copy -- if the programmer wants to

    preserve the stack, they can do that by writing programs that have the

    inputs and outputs that the combinator documents as required. That's a

    good habit. In fact, NOT doing it is such a disastrously bad habit that

    I don't understand why we're desiring to protect programmers from the

    consequences thereof.

    It's a very, very easy thing to ask for, and extremely easy to inference

    (if you want to do that). What do we gain by not asking for it?

     > > I'd say that copying the stack is a really, really bad habit... or

    > > at best, a habit that there's no good reason for and much good

    > > reason against.

    > Copying it if it's expensive is bad; if it's cheap, it's very useful.

     I concede that copying the stack is not "a bad habit". I overspoke. I

    disagree that it's useful, except for allowing programmers to write code

    that is bad in other ways (essentially, for producing side effects that

    the compiler promises to throw away).

     > In Factor, each conditional in 'cond' can alter the stack for the next

    > conditional. You need to use a lot of superfluous 'dup' functions to

    > avoid problems, and it removes a guarantee that you take for granted

    > in most languages (provided that you're not mutating any values in

    > your conditional).

     If you want that guarantee, you can use 'case' instead of 'cond'. If

    you're using 'cond' you're going to either use 'dup' (although I'd argue

    that there's nothing superfluous, and certainly not "a lot") or you're

    working your way through the stack for some other reason.

     > Things like this are the reason I'm not using Factor; I don't find

    > that sort of thing acceptable. Maybe Factor's stack inference could be

    > used to implement a 'cond' without these problems, but that's beyond

    > me unfortunately. Then again, I'm not a fan of smart combinators anyway.

     This is precisely why I don't like stack copying combinators: they claim

    to be smart about removing "accidental" side effects. How does it know

    which effects are accidental? Read the documentation. Well, strangely

    enough, that's exactly what I'd have to do in order to write code

    WITHOUT accidental side effects.

     > >> Since we have lost the object/function ambiguity, we can now express

    > >> the semantics of our functions in terms of application. I propose the

    > >> syntax '<object>:<function>' to indicate an application. Assuming our

    > >> concatenative language is stack-based, the object will always be a

    > >> stack.

    > > Wait, why couldn't this be done in the past?

    > My thinking was that if it's clear what is an object and what is a

    > function, then we can put only objects on the left and only functions

    > on the right. Without a way to represent objects, you can't really

    > represent application. This is not a problem in practice; Factor

    > certainly has a REPL that shows a stack with objects on it. I just

    > wanted to make things a bit more clear.

     I do like the notation you propose. I hope we see it regularly. The

    current equivalent is quoted single letter, which is good enough if you

    assume/require closed quotations.

     > - John

     -Wm

## John Nowak — 2009-03-05 22:09:18

    On Mar 5, 2009, at 1:03 PM, William Tanksley wrote:

     > John Nowak wrote:

    >

    >> William Tanksley wrote:

    >>

    >>> I agree that this would be a great way to structure the banana

    >>> combinator. I don't know why this would only work on Joy -- your

    >>> banana combinator doesn't ever copy the stack, or at least it

    >>> doesn't

    >>> require a stack copy.

    >>

    >> It does require a stack copy in a naive implementation because an

    >> identical stack is given to every function. Factor can typically

    >> avoid

    >> the stack copy thanks to its stack inference.

    >

    > I'd simply not perform the stack copy -- if the programmer wants to

    > preserve the stack, they can do that by writing programs that have the

    > inputs and outputs that the combinator documents as required.

     The banana combinator gives all functions access to the "same" stack.

    You have no choice but to copy the stack or to infer the stack effects

    of all functions in the combinator and pass them the appropriate sub-

    stacks.

     > That's a good habit. In fact, NOT doing it is such a disastrously

    > bad habit that I don't understand why we're desiring to protect

    > programmers from the consequences thereof.

     I'm not solely suggesting you do it to protect programmers from

    mistakes; I'd also suggest you do it because it allows for more things

    to be conveniently expressed.

     > I concede that copying the stack is not "a bad habit". I overspoke.

    > I disagree that it's useful

     I'm going to be irritating and claim that you're not being imaginative

    enough. Here's a function I often use in Joy programming:

        S [x0..xN] [F] map/w  ==  S [[S x0 F] first .. [S xN F] first]

    Essentially, each application of the function gets access to one

    element of the list and the entire stack. Unlike the 'map' combinator

    in Factor however, the function does not need to be careful to copy

    things around on the stack so that successive invocations of the

    function get the same view of the stack. Not only does this make

    reasoning easier, but you also can do nice things like this:

        5 [1 2 3] [+] map/w  ==  5 [6 7 8]

    This is just one example of course. You can probably think of others.

     > If you want that guarantee, you can use 'case' instead of 'cond'.

     Case is less general than cond.

     > If you're using 'cond' you're going to either use 'dup' (although

    > I'd argue

    > that there's nothing superfluous, and certainly not "a lot") or you're

    > working your way through the stack for some other reason.

     Yeah, you can make it work. I'd prefer to just have it guaranteed.

    Having one conditional alter what the next one sees is never

    desirable. If you want that, use nested conditionals and make it

    explicit. Ruling out undesirable behavior is a good thing. If you're

    using a language like Joy where "copying" the stack is cheap, I can't

    see why you *wouldn't* want a 'cond' that works such a way.

     > This is precisely why I don't like stack copying combinators: they

    > claim

    > to be smart about removing "accidental" side effects. How does it know

    > which effects are accidental?

     That's not what I'd say their claim is; see the 'map/w' example above

    or the banana combinator:

        4 3 2 (| + , - |)  ==  4 5 1

    - John