# Barebone implementation of concatenative language in c or c++

## blazeski — 2010-05-11 22:50:49

    Could someone  recommend a minimalistic implementation of a concatenative language written in c or c++?

    thanks

    Slobodan

## William Tanksley, Jr — 2010-05-11 23:16:15

    blazeski <blaseski@...> wrote:

     > Could someone  recommend a minimalistic implementation of a concatenative

    > language written in c or c++?

    >

     Isn't Joy written in C? (I don't recall.)

    There are plenty of Forths... Is that sufficient? If so, you might possibly

    want to look at FICL, which is actually widely used.

    I've never heard of 'libokit' before, but it's apparently a library for

    writing concatenative languages which have support for automatic memory

    management. Perhaps it could help (it comes with a demo language)?

    Slobodan

     >

     -Wm

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

## John Cowan — 2010-05-11 23:49:46

    William Tanksley, Jr scripsit:

     > Isn't Joy written in C? (I don't recall.)

     Yes, it is.  It depends only on ANSI C features.  I also have about 60%

    of an implementation written in Chicken Scheme, which compiles down to C.

    --

    How they ever reached any  conclusion at all    <cowan@...>

    is starkly unknowable to the human mind.        http://www.ccil.org/~cowan

            --"Backstage Lensman", Randall Garrett

## blazeski — 2010-05-12 09:52:12

    Thanks for the tips will take a look at them.

    I'm writing some c++ code and I want to include a minimalistic scheme  for scripting (I don't need GC but I must support native types). Then I got a suggestion that concatenative language naive implementation might be even simpler. So I'm basically looking for a source code of a toy example.

    Slobodan

## William Tanksley, Jr — 2010-05-12 14:37:30

    blazeski <blaseski@...> wrote:

     > Thanks for the tips will take a look at them.

    > I'm writing some c++ code and I want to include a minimalistic scheme  for

    > scripting (I don't need GC but I must support native types). Then I got a

    > suggestion that concatenative language naive implementation might be even

    > simpler. So I'm basically looking for a source code of a toy example.

    >

     Ah, yes; if you don't want/need GC you're likely well off to use a decent

    embeddable Forth with an object system, and FICL is designed for and has

    been extensively used for exactly that. If you needed/were-OK-with GC you'd

    be fine with Scheme itself, or Lua. (I don't know of any concatenative/GC

    language that's been designed to be embedded, which is something of a pity.)

     > Slobodan

     -Wm

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

## John Cowan — 2010-05-12 17:13:26

    William Tanksley, Jr scripsit:

     > Ah, yes; if you don't want/need GC you're likely well off to use a decent

    > embeddable Forth with an object system, and FICL is designed for and has

    > been extensively used for exactly that. If you needed/were-OK-with GC you'd

    > be fine with Scheme itself, or Lua. (I don't know of any concatenative/GC

    > language that's been designed to be embedded, which is something of a pity.)

     Let me put in a plug for Chibi Scheme, which is a full R5RS Scheme (with

    GC, of course) that is designed for embedding.  It's a small but fast

    bytecode interpreter in the style of Lua, but less limited.

    (Not that Lua doesn't have its own good points.)

    --

    I suggest you solicit aid of my followers       John Cowan

    or learn the difficult art of mud-breathing.    cowan@...

            --Great-Souled Sam                      http://www.ccil.org/~cowan

## blazeski — 2010-05-12 18:23:27

    I'm really grateful for suggested implementations, and I'm sure that those are useful even in production environment. However I'm looking for a toy implementation so I could quickly understand what happens under the hood of stack languages. Something designed for pedagogical purposes not for speed or efficiency. Something small enough that could be written over the weekend from scratch and contains just the bare minimum of the stack operations so it could be called interpreter.

     Or if you can't think of something like that what are the bare minimum of operators so I could call a language concatenative:

    For example from reading Brent Kerby Theory of concatenative combinators http://tunes.org/~iepos/joy.html if I implement : swap, dup, zap, unit, cat, cons, i, dip + (numbers and symbols) would that be enough to have a primitive joy like language?

## Jeremy Cowgar — 2010-05-12 18:25:49

    On 5/12/2010 2:23 PM, blazeski wrote:

     >

    > I'm really grateful for suggested implementations, and I'm sure that

    > those are useful even in production environment. However I'm looking

    > for a toy implementation so I could quickly understand what happens

    > under the hood of stack languages.

    >

     http://4.flowsnake.org/archives/252

    Jeremy

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

## William Tanksley, Jr — 2010-05-12 19:02:47

    The smallest possible number of required functions is 2... You need a data

    pseudo-combinator and an execution combinator. But this isn't helpful :-). I

    wrote a language that does that, and it's not in any way useful. If you want

    to look, it's at http://bitbucket.org/wtanksleyjr/tworing, but be warned...

    It's not pretty.

    There are a lot of one-day Forth implementations out there, but most of them

    don't try to have just a minimal number of words; that gets really difficult

    without garbage collection.

    minForth looks like it might be a consideration for you... But I'd still

    look at FICL, which is really well-tested. Rainbow Forth is _really_ simple

    (most of the Machine Forth derivatives are), but the need to trust machine

    code and read assembly might be too much.

    Hmm, someone did some research... Check out

    http://groups.google.com/group/comp.lang.forth/msg/10872cb68edcb526?pli=1 for

    some answers to the question (although it doesn't link to any source).

    Most of what I see is designed to be minimal and usable, not to be simply

    minimal.

    -Wm

    blazeski <blaseski@...> wrote:

     > I'm really grateful for suggested implementations, and I'm sure that those

    > are useful even in production environment. However I'm looking for a toy

    > implementation so I could quickly understand what happens under the hood of

    > stack languages. Something designed for pedagogical purposes not for speed

    > or efficiency. Something small enough that could be written over the weekend

    > from scratch and contains just the bare minimum of the stack operations so

    > it could be called interpreter.

    >  Or if you can't think of something like that what are the bare minimum of

    > operators so I could call a language concatenative:

    > For example from reading Brent Kerby Theory of concatenative combinators

    > http://tunes.org/~iepos/joy.html if I implement : swap, dup, zap, unit,

    > cat, cons, i, dip + (numbers and symbols) would that be enough to have a

    > primitive joy like language?

    >

    >

    >

    >

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

    >

    > Yahoo! Groups Links

    >

    >

    >

    >

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

## john@johnnowak.com — 2010-05-12 19:28:26

    On Wed, 12 May 2010 18:23:27 -0000, "blazeski" <blaseski@...> wrote:

     > For example from reading Brent Kerby Theory of concatenative combinators

    > http://tunes.org/~iepos/joy.html if I implement : swap, dup, zap, unit,

    > cat, cons, i, dip + (numbers and symbols) would that be enough to have a

    > primitive joy like language?

     The "classical" base seems to be swap, dup, drop, dip, cons, uncons, null,

    and if. These are easy to implement in any sort of extended lambda

    calculus

    by treating the stack as nested tuples (with ':' as cons and '->,' as

    cond):

    swap   = \(a, (b, s)). (b, (a, s))

    dup    = \(a, s). (a, (a, s))

    drop   = \(a, s). s

    dip    = \(a, (b, s)). (b, a s)

    null   = \s. ([], s)

    cons   = \(a, (b, s)). (a:b, s)

    uncons = \(a:b, s). (a, (b, s))

    if     = \(a, (b, (c, s))). a -> b s, c s

    More minimal bases are possible, but the above set is the most direct.

    - jn

## Ruurd — 2010-05-18 11:16:40

    If you want a minimal implementation:

    http://github.com/jdp/concom

    Or, if you want it to be like joy:

    http://www.latrobe.edu.au/philosophy/phimvt/sympas/s42minjoy.html

    concom does not have numbers; the small joy version has numbers, characters, booleans, symbols and it has more operators than concom.

    Joy is built up from three concepts: concatenative notation, quotations and combinators. The structured programming paradigm is built from the concepts: sequencing, selection, iteration, subroutines, arrays. When comparing the two paradigms: concatenative notation is roughly the same as sequencing; selection and iteration are covered by combinators; subroutines and arrays by quotations.

    When comparing Joy to other functional programming languages, it looks like Joy does not hide data, but makes it accessible on a stack. Other functional programming languages hide data in the parameters to their functions. Having data accessible means that it is possible to think about Joy is if it were an imperative programming language. But it is not, because it does not have assignment.

    And it is not a stack language either. The order of evaluation is not specified. Take for instance a small example: 2 3 [+] i. This evaluates to 5, but I do not have to start the rewriting at the left.[+] i is equal to + and 2 3 + is equal to 5, so I can start at the right if I like.

     > For example from reading Brent Kerby Theory of concatenative combinators http://tunes.org/~iepos/joy.html if I implement : swap, dup, zap, unit, cat, cons, i, dip + (numbers and symbols) would that be enough to have a primitive joy like language?

    >

## john@johnnowak.com — 2010-05-18 16:19:03

    On Tue, 18 May 2010 11:16:40 -0000, "Ruurd" <r.wiersma26@...>

    wrote:

     > And it is not a stack language either. The order of evaluation is not

    > specified. Take for instance a small example: 2 3 [+] i. This evaluates

     to

     > 5, but I do not have to start the rewriting at the left.[+] i is equal

     to +

     > and 2 3 + is equal to 5, so I can start at the right if I like.

     A critique of ascribing this property to Joy if I may...

    This view breaks down once your functions have side effects (which is the

    case in Joy). Because if this, the arbitrary order reduction you're

    talking

    about needs to be subject to side constraints regarding purity.

    The utility of arbitrary order rewriting in Joy is also severely limited

    by

    the fact that quotations are not opaque. For example, it is not valid to

    rewrite [1 2 +] to [3] because the quotation may be treated as a list

    later

    on. It is for this reason that I consider Joy's approach to quotations to

    be

    broken; a separation of quotations from lists would solve the problem.

    However, even if you do separate lists from quotations, you will end up

    with

    other concerns about arbitrary order reduction. For example, you may have

    a

    rule like '{A} drop == id' (where '{A}' denotes some list A), but that

    rule

    will not be valid in the presence of strict evaluation if you have partial

    functions (as Joy does).

    In short, you can say it isn't a stack language because it doesn't need to

    be evaluated in that order, but in practice you likely want it to be, and

    I believe the current Joy implementation takes this approach.

    Finally, applicative languages arguably have an advantage over Joy in

    terms

    of arbitrary order reduction. For example, take this Haskell function:

      bi f g x = (f x, g x)

    And the rough Joy equivalent:

      x [F] [G] bi = x F x G

    The Haskell version has the advantage that we can easily reduce 'f x'

    completely independent of 'g x'. The Joy version does not have this

    advantage; in general, it will be necessary to reduce 'x F' before it is

    safe to reduce 'x G' because 'G' may require more than one element on the

    stack. Accordingly, the applicative approach has the advantage here in

    terms

    of order-independent reduction.

    - jn

## john@johnnowak.com — 2010-05-18 16:41:27

    Sorry -- here's a copy slightly less mangled by my horrible webmail:

    On Tue, 18 May 2010 11:16:40 -0000, "Ruurd" <r.wiersma26@...>

    wrote:

     > And it is not a stack language either. The order of

    > evaluation is not specified. Take for instance a small

    > example: 2 3 [+] i. This evaluates to 5, but I do not

    > have to start the rewriting at the left.[+] i is equal

    > to + and 2 3 + is equal to 5, so I can start at the

    > right if I like.

     A critique of ascribing this property to Joy if I may...

    This view breaks down once your functions have side effects (which is the

    case in Joy). Because if this, the arbitrary order reduction you're talking

    about needs to be subject to side constraints regarding purity.

    The utility of arbitrary order rewriting in Joy is also severely limited

    by the fact that quotations are not opaque. For example, it is not valid to

    rewrite [1 2 +] to [3] because the quotation may be treated as a list later

    on. It is for this reason that I consider Joy's approach to quotations to

    be broken; a separation of quotations from lists would solve the problem.

    However, even if you do separate lists from quotations, you will end up

    with other concerns about arbitrary order reduction. For example, you may

    have a rule like '{A} drop == id' (where '{A}' denotes some list formed by

    the list of expressions A), but that rule will not be valid in the presence

    of strict evaluation if you have partial functions (as Joy does).

    In short, you can say it isn't a stack language because it doesn't need to

    be evaluated in a particular order, but in practice you likely want it to

    be, and I believe the current Joy implementation takes this approach.

    Finally, applicative languages arguably have an advantage over Joy in

    terms of arbitrary order reduction. For example, take this Haskell

    function:

      bi f g x = (f x, g x)

    And the common Joy equivalent:

      x [F] [G] bi = x F x G

    The Haskell version has the advantage that we can easily reduce 'f x'

    completely independent of 'g x'. The Joy version does not have this

    advantage; in general, it will be necessary to reduce 'x F' before it is

    safe to reduce 'x G' because 'G' may require more than one element on the

    stack. Accordingly, the applicative approach has the advantage here in

    terms of order-independent reduction.

    - jn

## Ruurd — 2010-05-18 17:49:52

    I'll respond to this one.

    Side effects. Then usual culprits are I/O. Now suppose I have a program: get 3 [+] i. I can still proceed from right to left, except that when I am about to execute + I do not find two numbers, but a function and a number. So 'get' must be evaluated before + is evaluated. This means that when + finds something that is a function, it has to invoke the function before proceeding with the addition.

    Quotations. If A, B, C, D, E are valid programs and B == D E, then A B C == A D E C and vice versa. That leaves the question: what is a valid program. The empty program is valid. A program that has a matching number of [ and ] is valid. When this rule is followed it will not be possible to substitute within a quotation, because then I would have to choose in your example: A == [, D == 1, E == 2 +, C == ], B == 3; A and C are not valid programs according to the definition.

    In your example: x [F] [G] bi = x F x G it depends on the arity of G whether it can be executed first, doesn't it? If it does not need something on the stack left there by F, then it can be executed first.

    The current implementation uses a stack, yes. But I was not talking about implementations, I was talking about the language and the way that I, as a person, can evaluate expressions in whatever order I like. If I can do that, mentally or on paper, it is a property of Joy, the language. Manfred also thinks that it should be possible to build Joy, the implementation, as a rewriting system: http://www.latrobe.edu.au/philosophy/phimvt/joy/j07rrs.html, so who am I to question that?

     --- In concatenative@yahoogroups.com, <john@...> wrote:

    >

    > Sorry -- here's a copy slightly less mangled by my horrible webmail:

    >

    > On Tue, 18 May 2010 11:16:40 -0000, "Ruurd" <r.wiersma26@...>

    > wrote:

    >

    > > And it is not a stack language either. The order of

    > > evaluation is not specified. Take for instance a small

    > > example: 2 3 [+] i. This evaluates to 5, but I do not

    > > have to start the rewriting at the left.[+] i is equal

    > > to + and 2 3 + is equal to 5, so I can start at the

    > > right if I like.

    >

    > A critique of ascribing this property to Joy if I may...

    >

    > This view breaks down once your functions have side effects (which is the

    > case in Joy). Because if this, the arbitrary order reduction you're talking

    > about needs to be subject to side constraints regarding purity.

    >

    > The utility of arbitrary order rewriting in Joy is also severely limited

    > by the fact that quotations are not opaque. For example, it is not valid to

    > rewrite [1 2 +] to [3] because the quotation may be treated as a list later

    > on. It is for this reason that I consider Joy's approach to quotations to

    > be broken; a separation of quotations from lists would solve the problem.

    >

    > However, even if you do separate lists from quotations, you will end up

    > with other concerns about arbitrary order reduction. For example, you may

    > have a rule like '{A} drop == id' (where '{A}' denotes some list formed by

    > the list of expressions A), but that rule will not be valid in the presence

    > of strict evaluation if you have partial functions (as Joy does).

    >

    > In short, you can say it isn't a stack language because it doesn't need to

    > be evaluated in a particular order, but in practice you likely want it to

    > be, and I believe the current Joy implementation takes this approach.

    >

    > Finally, applicative languages arguably have an advantage over Joy in

    > terms of arbitrary order reduction. For example, take this Haskell

    > function:

    >

    >   bi f g x = (f x, g x)

    >

    > And the common Joy equivalent:

    >

    >   x [F] [G] bi = x F x G

    >

    > The Haskell version has the advantage that we can easily reduce 'f x'

    > completely independent of 'g x'. The Joy version does not have this

    > advantage; in general, it will be necessary to reduce 'x F' before it is

    > safe to reduce 'x G' because 'G' may require more than one element on the

    > stack. Accordingly, the applicative approach has the advantage here in

    > terms of order-independent reduction.

    >

    > - jn

    >

## John Cowan — 2010-05-18 18:42:16

    john@... scripsit:

     > This view breaks down once your functions have side effects (which is the

    > case in Joy). Because if this, the arbitrary order reduction you're talking

    > about needs to be subject to side constraints regarding purity.

     Quite so.  Joy, like ML or Pure, is an eager impure functional programming

    language.  Consequently, arbitrary reordering is not permitted.

     > The utility of arbitrary order rewriting in Joy is also severely limited

    > by the fact that quotations are not opaque. For example, it is not valid to

    > rewrite [1 2 +] to [3] because the quotation may be treated as a list later

    > on. It is for this reason that I consider Joy's approach to quotations to

    > be broken; a separation of quotations from lists would solve the problem.

     If you consider it a problem.  I consider it one of Joy's special beauties:

    the abstraction for a sequence of datums is the same as the abstraction for

    a non-primitive function, which is just a sequence of functions.

     > Finally, applicative languages arguably have an advantage over Joy in

    > terms of arbitrary order reduction. For example, take this Haskell

    > function:

     I don't think your example has anything to do with applicativeness, but

    with purity and laziness.  A pure lazy concatenative language would have

    the same strengths (and weaknesses) as Haskell.

    --

    Kill Gorgun!  Kill orc-folk!            John Cowan

    No other words please Wild Men.         cowan@...

    Drive away bad air and darkness         http://www.ccil.org/~cowan

    with bright iron!   --Ghan-buri-Ghan    http://www.ccil.org/~cowan

## John Cowan — 2010-05-18 18:45:49

    Ruurd scripsit:

     > Side effects. Then usual culprits are I/O. Now suppose I have a program:

    > get 3 [+] i. I can still proceed from right to left, except that when

    > I am about to execute + I do not find two numbers, but a function and

    > a number. So 'get' must be evaluated before + is evaluated. This means

    > that when + finds something that is a function, it has to invoke the

    > function before proceeding with the addition.

     This amounts to creating a lazy variety of Joy, a perfectly good idea,

    but not equivalent to standard Joy, any more than Haskell is ML.

     > The current implementation uses a stack, yes. But I was not talking

    > about implementations, I was talking about the language and the

    > way that I, as a person, can evaluate expressions in whatever

    > order I like. If I can do that, mentally or on paper, it is a

    > property of Joy, the language.

     Only it's not.

     > Manfred also thinks that it should be possible to

    > build Joy, the implementation, as a rewriting system:

    > http://www.latrobe.edu.au/philosophy/phimvt/joy/j07rrs.html, so who

    > am I to question that?

     Sure, but it would have to be an eager impure rewriting system.  Which is

    what Pure is.

    --

    Verbogeny is one of the pleasurettes    John Cowan <cowan@...>

    of a creatific thinkerizer.             http://www.ccil.org/~cowan

       --Peter da Silva

## Ruurd — 2010-05-18 19:53:32

    We seem to disagree about what a language is. In my dictionary a language consists of: pronunciation, syntax, semantics. It seems to me that stack or rewriting is part of the semantics and therefore part of the language. If I have a simple expression like: 2 3 +, there is no way for you to convince me that this must be executed on a stack. I only see three symbols that in the next evaluation step are replaced by one symbol.

    Making a lazy Joy is quite unnecessary, because there is already a lazy library: http://www.latrobe.edu.au/philosophy/phimvt/joy/jp-reprod.html

     --- In concatenative@yahoogroups.com, John Cowan <cowan@...> wrote:

    > > The current implementation uses a stack, yes. But I was not talking

    > > about implementations, I was talking about the language and the

    > > way that I, as a person, can evaluate expressions in whatever

    > > order I like. If I can do that, mentally or on paper, it is a

    > > property of Joy, the language.

    >

    > Only it's not.

## John Nowak — 2010-05-18 23:03:49

    On 05/18/2010 01:49 PM, Ruurd wrote:

     >

    > I'll respond to this one.

    >

    > Side effects. Then usual culprits are I/O.

     > Now suppose I have a program: get 3 [+] i.

     > I can still proceed from right to left,

     > except that when I am about to execute + I

    > do not find two numbers, but a function

    > and a number. So 'get' must be evaluated

    > before + is evaluated. This means that

    > when + finds something that is a function,

     > it has to invoke the function before

     > proceeding with the addition.

     But that's not all. If 'f' and 'g' both take one argument on the stack

    and I have the program 'x f y g' where x and y are values, I can only

    evaluate 'g' before 'f' if I know 'f' is pure and total. This is not

    really an interesting property of Joy at all. Any functional language

    allows arbitrary order reduction such cases (e.g. '(f x, g y)').

     > Quotations. If A, B, C, D, E are valid

     > programs and B == D E, then A B C ==

     > A D E C and vice versa. That leaves the

     > question: what is a valid program. The

     > empty program is valid. A program that

     > has a matching number of [ and ] is valid.

     That's actually not true. For example, '+' is not a valid program. It's

    a valid expression, but not every expression is a valid program.

     > When this rule is followed it will not

     > be possible to substitute within a

     > quotation, because then I would have to

     > choose in your example: A == [, D == 1,

     > E == 2 +, C == ], B == 3; A and C are

     >  not valid programs according to the

     > definition.

     I think you've misunderstood me. My point is that, for example:

        1 2 +  ==  3

        [1 2 +]  /=  [3]       (because [1 2 +] head  /=  [3] head)

    This is because Joy's quotations are not opaque. In languages that offer

    abstractions (typically via lambda), you don't have this problem as it

    is safe to simplify within abstractions. Not offering abstractions and

    providing no way to implement them is an objectively bad thing. I see

    nothing good about this aspect of Joy.

     > In your example: x [F] [G] bi = x F x G

     > it depends on the arity of G whether it

     >  can be executed first, doesn't it?

     Yes, and that's exactly the problem. After all, determining the arity of

    G is, in general, undecidable!

     > The current implementation uses a stack,

     > yes. But I was not talking about

     > implementations, I was talking about the

     > language and the way that I, as a person,

     > can evaluate expressions in whatever order

     > I like. If I can do that, mentally or on

     > paper, it is a property of Joy, the

     > language.

     But that's not a reason to say Joy isn't a stack-based language. By your

    logic, neither is Forth! Indeed it is possible to compile Forth to a

    language like C without using a stack at all (given some minor

    restrictions such as that both branches of a conditional must have the

    same stack effect).

    - jn

## John Nowak — 2010-05-18 23:53:48

    On 05/18/2010 02:42 PM, John Cowan wrote:

     > If you consider it a problem.  I consider it one of Joy's special beauties:

    > the abstraction for a sequence of datums is the same as the abstraction for

    > a non-primitive function, which is just a sequence of functions.

     Sure, it's simple, but what's beautiful about it? It's a bit like having

    Scheme without lambda really. I believe Pico Lisp takes an approach

    similar to this, but no other Lisp I've aware of does, and for good

    reason. If given the choice between a language with the ability to

    construct abstractions and one without, all other things being equal,

    I'm certainly opting for the former. I can't think of an instance where

    I wouldn't.

     >> Finally, applicative languages arguably have an advantage over Joy in

    >> terms of arbitrary order reduction. For example, take this Haskell

    >> function:

    >

    > I don't think your example has anything to do with applicativeness, but

    > with purity and laziness.  A pure lazy concatenative language would have

    > the same strengths (and weaknesses) as Haskell.

     Perhaps I've made my point poorly. I'm actually pointing at the lack of

    many nice algebraic laws in Joy precisely because Joy is concatenative.

    Laziness has nothing to do with it. Look at my example again:

       Haskell:  bi f g x = (f x, g x)

       Joy:      x [F] [G] bi = x F x G

    The issue is that the 'bi' in Haskell always permits arbitrary order

    reduction whereas determining if it is possible in the Joy version is

    undecidable. This is true regardless of concerns related to strictness.

    This is a general problem with Joy. For example, the following law holds

    in Haskell:

       map f . map g  ==  map (f . g)

    However, the following does *not* hold in Joy:

       [F] map [G] map  ==  [F G] map

       (where [F] map = [null?] [] [uncons [F] dip [F] map cons] ifte)

    Similar issues hold for other functions like fold. The source of the

    problem is the fact that all functions in Joy are lifted to operate on

    products (i.e. the stack). This makes it difficult or impossible to

    write higher order functions that have the usual laws because it is

    difficult or impossible to prevent functions from accessing arbitrary

    amounts of the program's state. For example, the above law for map does

    hold with the side condition that 'F' has a stack effect of ( x -- y ).

    Manfred's "The Algebra of Joy" talks about Joy's suitability for

    equational reasoning and algebraic manipulation, but I'm of the opinion

    that it's not actually very good in this regard. I'd actually say that

    languages like Clean or Haskell -- or better yet, something like

    Charity, Squiggol, or Hagino's CPL -- are far better in this regard.

    This is doubly true since Joy offers no control over effects.

    This is not to say that Joy is not interesting is other ways of course.

    However, I'm of the opinion nowadays that it fails in its (primary?)

    objective of providing simple and powerful algebraic manipulation. It's

    for this reason that I've generally lost interest in concatenative

    languages.

    Please correct me if I'm wrong on any of my points.

    - jn

## John Cowan — 2010-05-19 03:27:19

    John Nowak scripsit:

     > Sure, it's simple, but what's beautiful about it? It's a bit like having

    > Scheme without lambda really.

     Scheme (and other applicative languages) need lambda or something like

    it because they need to bind names locally.  Joy has only global names,

    so it doesn't need any such abstraction: non-primitive functions are

    literally nothing but lists of objects, where every object in Joy has

    both a datum interpretation ('3' means 3) and a function interpretation

    ('3' means "accept a sequence, return an equivalent sequence but with

    3 pushed on it").

     > If given the choice between a language with the ability to

    > construct abstractions and one without, all other things being equal,

    > I'm certainly opting for the former. I can't think of an instance where

    > I wouldn't.

     Well, given the choice I'd rather have a language that binds local names,

    which is why I'm a Joy implementer but not a Joy user.  Although, as Henry

    Baker showed, a lambda-based language without assignment and with single-use

    names is equivalent to a concatenative language.

     > Look at my example again:

    >

    >    Haskell:  bi f g x = (f x, g x)

    >    Joy:      x [F] [G] bi = x F x G

    >

    > The issue is that the 'bi' in Haskell always permits arbitrary order

    > reduction whereas determining if it is possible in the Joy version is

    > undecidable. This is true regardless of concerns related to strictness.

     But Haskell only permits arbitrary-order reduction *because* it is

    pure and lazy.  If you define bi in ML, you'll get a function which

    must be evaluated left to right, because it returns bottom if f does.

    That's why I say concatenation is not directly relevant.

     > Similar issues hold for other functions like fold. The source of the

    > problem is the fact that all functions in Joy are lifted to operate on

    > products (i.e. the stack). This makes it difficult or impossible to

    > write higher order functions that have the usual laws because it is

    > difficult or impossible to prevent functions from accessing arbitrary

    > amounts of the program's state. For example, the above law for map does

    > hold with the side condition that 'F' has a stack effect of ( x -- y ).

     That's true.  Note, however, that the "map law" doesn't hold for Scheme

    either, except with the side condition that F returns just once and with

    just one value.

     > Manfred's "The Algebra of Joy" talks about Joy's suitability for

    > equational reasoning and algebraic manipulation, but I'm of the opinion

    > that it's not actually very good in this regard. I'd actually say that

    > languages like Clean or Haskell -- or better yet, something like

    > Charity, Squiggol, or Hagino's CPL -- are far better in this regard.

     Or Pure, which directly does equational reasoning.

    --

    Schlingt dreifach einen Kreis vom dies!    John Cowan <cowan@...>

    Schliesst euer Aug vor heiliger Schau,     http://www.ccil.org/~cowan

    Denn er genoss vom Honig-Tau,

    Und trank die Milch vom Paradies.            --Coleridge (tr. Politzer)

## John Cowan — 2010-05-19 03:31:01

    Ruurd scripsit:

     > We seem to disagree about what a language is. In my dictionary a

    > language consists of: pronunciation, syntax, semantics. It seems to me

    > that stack or rewriting is part of the semantics and therefore part of

    > the language. If I have a simple expression like: 2 3 +, there is no

    > way for you to convince me that this must be executed on a stack. I

    > only see three symbols that in the next evaluation step are replaced

    > by one symbol.

     If you only look at the simple case 2+3, C looks pure and functional too.

    You have to examine the totality of the language.  But whether a stack

    is used or a series of rewrite rules is an implementation detail.

     > Making a lazy Joy is quite unnecessary, because there is already a lazy

    > library: http://www.latrobe.edu.au/philosophy/phimvt/joy/jp-reprod.html

     That library is about lazy lists, not about Haskell-style pervasive

    laziness.  In Haskell, all primitive functions notice whether their

    arguments are datums or thunks, and if they are thunks, they get forced;

    this is not provided in Joy.

    --

    But that, he realized, was a foolish            John Cowan

    thought; as no one knew better than he          cowan@...

    that the Wall had no other side.                http://www.ccil.org/~cowan

            --Arthur C. Clarke, "The Wall of Darkness"

## Ruurd — 2010-05-19 07:15:38

    > > Quotations. If A, B, C, D, E are valid

    >  > programs and B == D E, then A B C ==

    >  > A D E C and vice versa. That leaves the

    >  > question: what is a valid program. The

    >  > empty program is valid. A program that

    >  > has a matching number of [ and ] is valid.

    >

    > That's actually not true. For example, '+' is not a valid program. It's

    > a valid expression, but not every expression is a valid program.

     I dón't see why + is not a valid program. When executed it will give a runtime error when there is nothing to add, but validity is a syntactic property. (I have not said so, but with [ and ] I mean the tokens, not the characters). Also, according to the grammar of Joy:

    http://www.latrobe.edu.au/philosophy/phimvt/joy/j09imp.html

    there is no such thing as an expression. There is only term and factor, a term being equal to zero or more factors. And a program is a term, of course.

     >

    > > When this rule is followed it will not

    >  > be possible to substitute within a

    >  > quotation, because then I would have to

    >  > choose in your example: A == [, D == 1,

    >  > E == 2 +, C == ], B == 3; A and C are

    >  >  not valid programs according to the

    >  > definition.

    >

    > I think you've misunderstood me. My point is that, for example:

     No, I did not misunderstand you. I give rules that distinguish environments that allow substitution and environments where that is not allowed. It is not necessary to do substitution everywhere.

    If A and B are valid programs, then so is A B. This rule allows me to make programs bigger. The substitution rule allows me to inline if I favor speed or to factor out if I favor program size. I don't see any reason why I would want to simplify within an abstraction.

## blazeski — 2010-05-19 07:38:00

    Just what I was looking for, many thanks.

    Slobodan

     --- In concatenative@yahoogroups.com, "Ruurd" <r.wiersma26@...> wrote:

    >

    >

    >

    > If you want a minimal implementation:

    >

    > http://github.com/jdp/concom

    >

    > Or, if you want it to be like joy:

    >

    > http://www.latrobe.edu.au/philosophy/phimvt/sympas/s42minjoy.html

    >

    > concom does not have numbers; the small joy version has numbers, characters, booleans, symbols and it has more operators than concom.

    >

    > Joy is built up from three concepts: concatenative notation, quotations and combinators. The structured programming paradigm is built from the concepts: sequencing, selection, iteration, subroutines, arrays. When comparing the two paradigms: concatenative notation is roughly the same as sequencing; selection and iteration are covered by combinators; subroutines and arrays by quotations.

    >

    > When comparing Joy to other functional programming languages, it looks like Joy does not hide data, but makes it accessible on a stack. Other functional programming languages hide data in the parameters to their functions. Having data accessible means that it is possible to think about Joy is if it were an imperative programming language. But it is not, because it does not have assignment.

    >

    > And it is not a stack language either. The order of evaluation is not specified. Take for instance a small example: 2 3 [+] i. This evaluates to 5, but I do not have to start the rewriting at the left.[+] i is equal to + and 2 3 + is equal to 5, so I can start at the right if I like.

    >

    > > For example from reading Brent Kerby Theory of concatenative combinators http://tunes.org/~iepos/joy.html if I implement : swap, dup, zap, unit, cat, cons, i, dip + (numbers and symbols) would that be enough to have a primitive joy like language?

    > >

    >

## john@johnnowak.com — 2010-05-19 16:57:21

    On Tue, 18 May 2010 23:27:19 -0400, John Cowan <cowan@...> wrote:

     > John Nowak scripsit:

    >

    >> Sure, it's simple, but what's beautiful about it? It's a bit like

     having

     >> Scheme without lambda really.

    >

    > Scheme (and other applicative languages) need lambda or something like

    > it because they need to bind names locally.  Joy has only global names,

    > so it doesn't need any such abstraction: non-primitive functions are

    > literally nothing but lists of objects, where every object in Joy has

    > both a datum interpretation ('3' means 3) and a function interpretation

    > ('3' means "accept a sequence, return an equivalent sequence but with

    > 3 pushed on it").

     I think you're maybe missing my point. I'm aware Scheme needs lambda to

    bind names. However, there is no reason lambda needs to form *opaque*

    abstractions. In Pico Lisp, it does not; you can modify a lambda as if it

    were a pile of conses and atoms. In most Lisps, however, it does form

    opaque abstractions because of the many advantages of having your functions

    be opaque. I believe the benefits of opaque abstractions would apply to Joy

    regardless of the issue of binding.

     > But Haskell only permits arbitrary-order reduction *because* it is

    > pure and lazy.  If you define bi in ML, you'll get a function which

    > must be evaluated left to right, because it returns bottom if f does.

    > That's why I say concatenation is not directly relevant.

     Let me put it another way. It's easy to have a parallel 'bi' in an ML-like

    language with the type '(a -> b) -> (c -> d) -> (a, c) -> (b, d)'. You

    can't do this in the concatenative setting because bi has the type 'R a [R

    -> S] [S a -> T] -> T' and hence it is not possible to enforce that the

    quotation on the top of the stack does not use more than one element. You

    *could* give it a type like 'R a [R -> S] [a -> T] -> S ++ T', but this

    sort of type level concatenation is undecidable.

    Even if your language is eager and you're not considering parallel

    combinators, there are still benefits to the applicative approach. In

    particular, you can reduce and transform 'f x' in strictness-preserving

    ways without worrying about the arity of 'g x'. This is useful when doing

    algebraic manipulation of programs regardless of your evaluation mechanism.

    - jn

## William Tanksley, Jr — 2010-05-19 17:00:55

    John Nowak <john@...> wrote:

     > Sure, it's simple, but what's beautiful about it? It's a bit like having

    > Scheme without lambda really. I believe Pico Lisp takes an approach

    > similar to this, but no other Lisp I've aware of does, and for good

    > reason. If given the choice between a language with the ability to

    > construct abstractions and one without, all other things being equal,

    > I'm certainly opting for the former. I can't think of an instance where

    > I wouldn't.

     I also don't like how Joy uses the same notation for list literals as

    it does for function literals. Other concatenative languages don't do

    this. I don't understand the rest of your response, in particular the

    part about not being able to construct abstractions which seems so

    important to you.

     >>> Finally, applicative languages arguably have an advantage over Joy in

    >>> terms of arbitrary order reduction. For example, take this Haskell

    >>> function:

    >> I don't think your example has anything to do with applicativeness, but

    >> with purity and laziness.  A pure lazy concatenative language would have

    >> the same strengths (and weaknesses) as Haskell.

    > Perhaps I've made my point poorly. I'm actually pointing at the lack of

    > many nice algebraic laws in Joy precisely because Joy is concatenative.

     No. The parallel evaluation laws don't apply because concatenative

    languages are not tree-structured. The laws that apply are

    _different_. You can't criticize Greek because it doesn't use a roman

    alphabet -- although you could criticize ancient Egyptian for not

    using an alphabet at all, and English because it uses an overly

    complex phonetic system. Anyhow, before this set of criticism begins,

    you have to justly characterize the algebraic laws that DO apply,

    rather than mourning the ones that obviously do NOT.

     > Laziness has nothing to do with it. Look at my example again:

     Laziness is one of the things that can't easily be imported to a

    concatenative language.

     > The issue is that the 'bi' in Haskell always permits arbitrary order

    > reduction whereas determining if it is possible in the Joy version is

    > undecidable. This is true regardless of concerns related to strictness.

     In Joy it's undecidable. In Haskell it's decidable. The distinction

    between the two isn't that one is concatenative and the other is

    applicative; it's that Haskell's type system is designed to allow this

    kind of decision, while Joy isn't. There are concatenative languages

    which make deciding this linear in the size of the function

    (StrongForth, for example).

     > - jn

     -Wm

## john@johnnowak.com — 2010-05-19 17:04:52

    On Wed, 19 May 2010 07:15:38 -0000, "Ruurd" <r.wiersma26@...>

    wrote:

     > I don't see why + is not a valid program. When executed it will give a

    > runtime error when there is nothing to add, but validity is a syntactic

    > property.

     Validity is not, in general, a syntactic property (e.g. it may be rejected

    for type-level reasons). But yes, if you're considering the error resulting

    from such a program to be a well-defined result, then your program is

    technically valid. I'm not sure Joy is well-defined enough to answer this

    question properly. I'll concede that you're likely right in this cases

    though; my brain was stuck in typed mode as usual.

     >> I think you've misunderstood me. My point is that, for example:

    >

    > No, I did not misunderstand you. I give rules that distinguish

    > environments that allow substitution and environments where

    > that is not allowed. It is not necessary to do substitution

    > everywhere.

     No it isn't, but it's very, very useful if you're interested in algebraic

    manipulation of programs (which is, in my understanding, the principal

    issue that Manfred wanted to address with Joy).

    - jn

## john@johnnowak.com — 2010-05-19 17:16:06

    On Wed, 19 May 2010 11:57:21 -0500, <john@...> wrote:

     > Even if your language is eager and you're not considering parallel

    > combinators, there are still benefits to the applicative approach. In

    > particular, you can reduce and transform 'f x' in strictness-preserving

    > ways without worrying about the arity of 'g x'. This is useful when

     doing

     > algebraic manipulation of programs regardless of your evaluation

     mechanism.

    Final clarification. I mean you can apply rules like this without

    consideration for arity and coarity:

      cross f g . bi h i  ==  cross (f . h) (g . i)

        where bi f g x = (f x, g x)

              cross f g x y = (f x, g y)

    This is equivalent to a rule like the following in Joy except for the fact

    that, of course, this rule isn't remotely valid:

      [H] [I] bi [F] [G] bi*  ==  [H F] [I G] bi*

        where [F] [G] bi = [keep] dip i

              [F] [G] bi* = [dip] dip i

    It is, however, valid if all functions have a stack effect of ( x -- x ).

    Because the functions in the applicative version aren't lifted to operate

    on a stack, you don't have this issue.

    - jn

## john@johnnowak.com — 2010-05-19 17:21:05

    I am never posting at work again.

     >   cross f g . bi h i  ==  cross (f . h) (g . i)

     cross f g . bi h i  ==  bi (f . h) (g . i)

     >   [H] [I] bi [F] [G] bi*  ==  [H F] [I G] bi*

     [H] [I] bi [F] [G] bi*  ==  [H F] [I G] bi

    Argh!

    - jn

## pml060912 — 2010-05-20 14:32:38

    --- In concatenative@yahoogroups.com, "William Tanksley, Jr" <wtanksleyjr@...> wrote:

     >

    > John Nowak <john@...> wrote:

     .

    .

    .

     > > Laziness has nothing to do with it. Look at my example again:

    >

    > Laziness is one of the things that can't easily be imported to a

    > concatenative language.

     Well, that depends on what you call lazy. For Furphy, I worked out an indirection mechanism that allows you to produce the effect of laziness even when everything actually encountered is handled eagerly: the pair FREEZE and THAW, although you would usually use prefrozen code set up with syntactic sugar instead of FREEZE. FREEZE, THAW, and the syntactic sugar alternative are all quite easy to implement and to use. P.M.Lawrence.

## William Tanksley, Jr — 2010-05-21 14:23:37

    pml060912 <pml540114@...> wrote:

     > "William Tanksley, Jr" <wtanksleyjr@...> wrote:

    >> Laziness is one of the things that can't easily be imported to a

    >> concatenative language.

    > Well, that depends on what you call lazy.

     Actually, I don't think there's ambiguity in this context. A lazy

    language is one in which the semantics for the parameters to a

    function are performed only if the parameter is actually USED. This

    means that you can have a function with a parameter that cannot be

    evaluated completely, and the program will run if the parameter is not

    actually used in the function.

     > For Furphy,

     http://users.beagle.com.au/peterl/furphy.html (I think -- is that your

    latest work?).

     > I worked out an indirection mechanism that allows you

    > to produce the effect of laziness even when everything

    > actually encountered is handled eagerly: the pair

    > FREEZE and THAW,

     That's not a lazy language, I think. Unfortunately, I'm unqualified to

    judge, since I'm unable to read your examples; I have no idea where

    the words TRUE_OPTION and FALSE_OPTION are defined; they just appear

    there. (I vaguely recall having figured out how to read Furphy, but

    I've forgotten since.)

    The distinction is that in this language you have to explicitly mark

    the non-evaluated parts; a truly lazy language needs no such marker.

     > P.M.Lawrence.

     -Wm

## pml060912 — 2010-05-23 05:08:53

    --- In concatenative@yahoogroups.com, "William Tanksley, Jr" <wtanksleyjr@...> wrote:

     >

    > pml060912 <pml540114@...> wrote:

    > > "William Tanksley, Jr" <wtanksleyjr@> wrote:

    > >> Laziness is one of the things that can't easily be imported to a

    > >> concatenative language.

    >

    > > Well, that depends on what you call lazy.

    >

    > Actually, I don't think there's ambiguity in this context. A lazy

    > language is one in which the semantics for the parameters to a

    > function are performed only if the parameter is actually USED. This

    > means that you can have a function with a parameter that cannot be

    > evaluated completely, and the program will run if the parameter is not

    > actually used in the function.

     The indirection mechanism achieves that effect very simply, so it depends whether you are willing to call it lazy even though it is only delivering lazy semantics and isn't using lazy syntax to get there. But, since the mechanism is simple, it wouldn't be hard to set up a concatenative language that had syntactic sugar for that as well - making it both syntactically and semantically lazy. That's why I thought it was relevant.

     >

    > > For Furphy,

    >

    > http://users.beagle.com.au/peterl/furphy.html (I think -- is that your

    > latest work?).

     Well, the latest that's firmed up. I have been thinking about an operator that would "glue" two frozen words together to get a new (frozen) word, and which sorts of garbage collection would be the best choices.

     >

    > > I worked out an indirection mechanism that allows you

    > > to produce the effect of laziness even when everything

    > > actually encountered is handled eagerly: the pair

    > > FREEZE and THAW,

    >

    > That's not a lazy language, I think. Unfortunately, I'm unqualified to

    > judge, since I'm unable to read your examples; I have no idea where

    > the words TRUE_OPTION and FALSE_OPTION are defined; they just appear

    > there. (I vaguely recall having figured out how to read Furphy, but

    > I've forgotten since.)

     That "appearing" IS the definition, the first time they appear. With that kind of reverse polish naming, an unrecognised token closes the current definition and is assigned as its name. Here are the definitions from the example code again:-

    FREEZE TRUE_STUFF TRUE_OPTION

    FREEZE FALSE_STUFF FALSE_OPTION

    (I didn't define TRUE_STUFF and FALSE_STUFF.)

     >

    > The distinction is that in this language you have to explicitly mark

    > the non-evaluated parts; a truly lazy language needs no such marker.

     Since there is already some laziness, with nothing being done apart from immediate words until the source has been compiled, it would be easy enough to invert that so that everything is frozen unless deliberately invoked. You would just drop the "and go" feature from the compile and go compiler and also change new word definitions to default to frozen, leaving invocation up to suitable immediate words. On the whole I prefer this way around since it is a closer and more readable match to what is usually needed, but it does show that there isn't really a big problem implementing full laziness. P.M.Lawrence.

## Don Groves — 2010-05-23 06:49:08

    > --- In concatenative@yahoogroups.com, "William Tanksley, Jr"

    > <wtanksleyjr@...> wrote:

    >>

    >> pml060912 <pml540114@...> wrote:

    >>> "William Tanksley, Jr" <wtanksleyjr@> wrote:

    >>>> Laziness is one of the things that can't easily be imported to a

    >>>> concatenative language.

     It seems to me that laziness can be implemented simply by

    encapsulating all data in functions. If a particular function

    is not called, that data is not evaluated. What am I missing?

    don

## Ruurd — 2010-05-23 08:06:11

    Strictly False, mentioned in message #2834 (the link is still valid)also has quotations.

     --- In concatenative@yahoogroups.com, "William Tanksley, Jr" <wtanksleyjr@...> wrote:

    > I also don't like how Joy uses the same notation for list literals as

    > it does for function literals. Other concatenative languages don't do

    > this.

## Ruurd — 2010-05-23 08:23:18

    The discussion is partly about what laziness is and partly about whether the language supports it as the default evaluation mechanism.

    Haskell is lazy, Ocaml is strict. That is why Haskell is 9 times slower than Ocaml: http://www.cubbi.com/fibonacci.html

    The discussion is not about performance, but it does show that laziness comes with a price. Using lazy constructs in a strict language also comes with a price. Now it is the programmer who has to set up the construct, everywhere he needs it.

    By capturing data in a quotation Joy already offers lazy constructs. Of course, it is now up to the programmer to decide when and where the data is needed. Now the programmer can not be lazy.

     --- In concatenative@yahoogroups.com, Don Groves <dgroves@...> wrote:

    >

    > > --- In concatenative@yahoogroups.com, "William Tanksley, Jr"

    > > <wtanksleyjr@> wrote:

    > >>

    > >> pml060912 <pml540114@> wrote:

    > >>> "William Tanksley, Jr" <wtanksleyjr@> wrote:

    > >>>> Laziness is one of the things that can't easily be imported to a

    > >>>> concatenative language.

    >

    > It seems to me that laziness can be implemented simply by

    > encapsulating all data in functions. If a particular function

    > is not called, that data is not evaluated. What am I missing?

    >

    > don

    >

## Ruurd — 2010-05-23 09:00:21

    Joy is tree-structured. Also, the only thing that is usually needed to change a sequential program into a parallel evaluated program is to change map into pmap.

    As an example, look at Manfred's question about the quadratic formula in message #2176 and his answer in message #2228. His solution uses the ternary combinator to compute three subexpressions. These expressions can in theory be computed in parallel.

    When I thought about parallel evaluation, because computations can be done while the program is waiting for I/O to finish, I was advised not to use parallel evaluation for that purpose. It would be simpler to use non-blocking I/O functions.

    When thinking about a parallel language out of the many languages that claim to be parallel the only language that makes any sense is Erlang. Now that desktop processors are multicore, there is a lot of interest in a good parallel language with a nice and familiar syntax that is acceptable for mainstream programmers.

    --- In concatenative@yahoogroups.com, "William Tanksley, Jr" > No. The parallel evaluation laws don't apply because concatenative

     > languages are not tree-structured.

## William Tanksley, Jr — 2010-05-23 17:20:46

    Ruurd <r.wiersma26@...> wrote:

     > Joy is tree-structured.

     When you consider list and function literals, I admit there's a

    syntactic tree structure (and for Joy, function literals are essential

    to writing programs). But concatenative languages in general are not

    intrinsically tree-structured; applicative languages are, since every

    function call forms the root of a subtree. It's possible to define a

    library that allows one to write entirely flat programs in any

    concatenative language. (My current efforts on this front show that it

    is ugly and inconvenient when one attempts to be 100% "flat"; as with

    most things in programming, being satisfied with 99% purity is much

    better than going for 100%.)

     > Also, the only thing that is usually needed to change a sequential program into a parallel evaluated program is to change map into pmap.

     Unless I missed something, that wasn't what was being discussed; we

    were talking about implicit compiler support for parallelism, the sort

    of thing that allows compilers to generate decent code for modern

    (superscalar) architectures.

    Also... In general, "changing map into pmap" is insufficient (there

    are MANY other places for parallelism, and an explicit map is too

    rare) and often incorrect (map consumes and generates an ordered list,

    so computing in parallel simply means that the runtime will have to

    assemble the result list in the sequential order).

     > When I thought about parallel evaluation, because computations can be done while the program is waiting for I/O to finish, I was advised not to use parallel evaluation for that purpose. It would be simpler to use non-blocking I/O functions.

     Exactly -- one needs profound support for parallel computation, not

    merely a few quick changes.

     > When thinking about a parallel language out of the many languages that claim to be parallel the only language that makes any sense is Erlang. Now that desktop processors are multicore, there is a lot of interest in a good parallel language with a nice and familiar syntax that is acceptable for mainstream programmers.

     I largely agree. Except that I'm not sure about Erlang being the only

    thing that "makes any sense"; there are many other options that do

    much the same thing. Erlang is simply very well tested and supported.

    I'd like to see what might happen with a parallel version of k4 (a

    proprietary language from kx.com, a remote derivative of APL); more

    appropriately for this group, the concatenative languages Enchilada

    and Ripple, both of which are intrinsically parallel (although

    Enchilada is probably TOO parallel to be practical).

    -Wm

## William Tanksley, Jr — 2010-05-23 17:33:59

    Ruurd <r.wiersma26@...> wrote:

     > The discussion is partly about what laziness is and partly about whether the language supports it as the default evaluation mechanism.

     Yes.

     > Haskell is lazy, Ocaml is strict. That is why Haskell is 9 times slower than Ocaml: http://www.cubbi.com/fibonacci.html

     False -- Ocaml is fast because it's deliberately impure. This allows

    the programmer to make speed-related decisions, thus allowing the

    compiler to succeed with much less specialized optimization code.

    Haskell is slow because it is pure; the programmer is (essentially)

    not permitted to write code for speed (it's possible, but the result

    is extremely ugly code with TONS of interwoven monads). New Haskell

    compilers become MUCH faster as their optimizers become more

    sophisticated (I doubt that Ocaml still holds a 9x advantage).

    As I said in my last post, it's more practical to be 99% pure than 100%.

     > By capturing data in a quotation Joy already offers lazy constructs. Of course, it is now up to the programmer to decide when and where the data is needed. Now the programmer can not be lazy.

     I don't see how you can claim that allowing list literals is similar

    to being a lazy language. That simply destroys the meaning of the

    word, to the point that machine language becomes a lazy language.

    -Wm

## William Tanksley, Jr — 2010-07-16 17:21:20

    Don Groves <dgroves@...> wrote:

     >>>> "William Tanksley, Jr" <wtanksleyjr@> wrote:

    >>>>> Laziness is one of the things that can't easily be imported to a

    >>>>> concatenative language.

    > It seems to me that laziness can be implemented simply by

    > encapsulating all data in functions. If a particular function

    > is not called, that data is not evaluated. What am I missing?

     Data isn't supposed to be evaluated, of course; I think you meant

    encapsulating all functions in data rather than the other way around.

    And indeed, that does allow you to control when your parameters are

    evaluated (thus making them lazy); but it also makes tracking

    parameters part of writing and reading your program -- and a lot of

    that winds up being done at runtime.

    I guess my basic point is that there's a type of laziness, let's call

    it automatic laziness, that just can't be done in a concatenative

    language. Syntax sugar won't save you from that problem, I think,

    since there's too many operations that need to be done.

    This doesn't mean I don't like concatenative languages; I just think

    there's some research to be done in this area.

    You know, it occurs to me that one place to look for a starting point

    in that research might be colorforth. Take a look:

    http://rainbowforth.sourceforge.net/blocks.html (see block 36,

    'factorial', for a programlike block, most of the earlier stuff is the

    source code for the language, including a lot of machine code).

    Colorforth allows you to write code that's simply neutrally stored, or

    markers that help you access that stored code, or immediately executed

    code, or code that generates results that go into a definition...

    There's a lot of different things to do. The different operations are

    distinguished by color codes.

     > don

     -Wm

## Don Groves — 2010-07-21 03:18:00

    On 16 Jul 2010, at 10:21, William Tanksley, Jr wrote:

     > Don Groves <dgroves@...> wrote:

    >>>>> "William Tanksley, Jr" <wtanksleyjr@> wrote:

    >>>>>> Laziness is one of the things that can't easily be imported to a

    >>>>>> concatenative language.

    >>  It seems to me that laziness can be implemented simply by

    >> encapsulating all data in functions. If a particular function

    >> is not called, that data is not evaluated. What am I missing?

    >

    > Data isn't supposed to be evaluated, of course; I think you meant

    > encapsulating all functions in data rather than the other way around.

     OK, guess I may need some hand-holding here:

    Isn't call-by-reference essentially equivalent to lazy evaluation?

    If the called function doesn't need a certain parameter during a

    particular call, that parameter will not be evaluated. So, parameters

    (data) are only evaluated when needed, i.e., they are lazy.

    In a call-by-value environment, It seems to me that incapsulating

    all data in functions yields the same effect as call-by-reference. If

    a parameter is not needed, its evaluating function will not be called.

    If I'm on the wrong track with this, please enlighten me!

    don

     > And indeed, that does allow you to control when your parameters are

    > evaluated (thus making them lazy); but it also makes tracking

    > parameters part of writing and reading your program -- and a lot of

    > that winds up being done at runtime.

    >

    > I guess my basic point is that there's a type of laziness, let's call

    > it automatic laziness, that just can't be done in a concatenative

    > language. Syntax sugar won't save you from that problem, I think,

    > since there's too many operations that need to be done.

    >

    > This doesn't mean I don't like concatenative languages; I just think

    > there's some research to be done in this area.

    >

    > You know, it occurs to me that one place to look for a starting point

    > in that research might be colorforth. Take a look:

    > http://rainbowforth.sourceforge.net/blocks.html (see block 36,

    > 'factorial', for a programlike block, most of the earlier stuff is the

    > source code for the language, including a lot of machine code).

    > Colorforth allows you to write code that's simply neutrally stored, or

    > markers that help you access that stored code, or immediately executed

    > code, or code that generates results that go into a definition...

    > There's a lot of different things to do. The different operations are

    > distinguished by color codes.

    >

    >> don

    >

    > -Wm

    >

    >

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

    >

    > Yahoo! Groups Links

    >

    >

    >

## John Nowak — 2010-07-21 04:11:10

    On 2010.07.20, at 11:18 PM, Don Groves wrote:

     > Isn't call-by-reference essentially equivalent to lazy evaluation?

     Nope. Call-by-reference is an abomination that shouldn't exist. Lazy evaluation is unrelated.

    A quick run through here should help:

    http://en.wikipedia.org/wiki/Evaluation_strategy

    Caveat: It is possible to have an eager yet non-strict language. Wikipedia conflates eagerness and strictness which is unfortunate, although most existing eager languages are indeed strict. The Id programming language is an example of an eager, non-strict language.

    Wikipedia is bad at precision.

     > In a call-by-value environment, It seems to me that incapsulating

    > all data in functions yields the same effect as call-by-reference.

     If you replace "call-by-reference" with "lazy evaluation" (or similar), then you're essentially right if your language has lambda abstractions under which evaluation does not occur until they're applied. Lazy evaluation will share the result of evaluating the parameter though if it is needed in multiple places. You have to manually memoize the function passed in to emulate this in an eager setting.

    Concatenative languages do not have lambda abstractions, but you can achieve a similar result by placing a function on the stack and lifting values into it (e.g. via Factor's misnamed 'curry' function; it really should be called 'partial-apply' or similar, although that's not exactly right either).

    - jn

## William Tanksley, Jr — 2010-07-21 04:18:15

    Don Groves <dgroves@...> wrote:

     > William Tanksley, Jr wrote:

    >> Don Groves <dgroves@...> wrote:

    >>>>>> "William Tanksley, Jr" <wtanksleyjr@> wrote:

    >>>>>>> Laziness is one of the things that can't easily be imported to a

    >>>>>>> concatenative language.

    >>>  It seems to me that laziness can be implemented simply by

    >>> encapsulating all data in functions. If a particular function

    >>> is not called, that data is not evaluated. What am I missing?

    >> Data isn't supposed to be evaluated, of course; I think you meant

    >> encapsulating all functions in data rather than the other way around.

    > OK, guess I may need some hand-holding here:

     No... It's just unclear presuppositions. Thanks for making them clear

    by asking about them.

     > Isn't call-by-reference essentially equivalent to lazy evaluation?

     No; C++ allows call by reference semantics (explicitly specified, of

    course) without being lazy at all. An early Fortran had implicit call

    by reference, again not lazy (but, I'm told, very dangerous). I don't

    use Perl, but I'm told it's call-by-reference.

    Wikipedia just reminded me that you're thinking of "call by name" or

    "call by need", but those are simply ways to achieve lazy evaluation.

     > If the called function doesn't need a certain parameter during a

    > particular call, that parameter will not be evaluated. So, parameters

    > (data) are only evaluated when needed, i.e., they are lazy.

     That IS what lazy evaluation is, yes.

     > In a call-by-value environment, It seems to me that encapsulating

    > all data in functions yields the same effect as call-by-reference. If

    > a parameter is not needed, its evaluating function will not be called.

     This gets confusing to me, so hold on tight... :-)

    In order to pass a function to a procedure, the function has to be

    available as data. If it's not, you can't pass it.

    Now, if your language is lazy (or non-strict) this doesn't matter; you

    can avoid executing the function by never mentioning its parameter on

    an execution path. This allows languages that don't provide

    higher-order functions to still be very expressive.

     > don

     -Wm

## William Tanksley, Jr — 2010-07-21 04:32:17

    John Nowak <john@...> wrote:

     > Don Groves wrote:

    >> Isn't call-by-reference essentially equivalent to lazy evaluation?

    > Nope. Call-by-reference is an abomination that shouldn't exist. Lazy evaluation is unrelated.

     Heh. John, is this because CBR hypothetically allows mutation of

    arbitrary items? I'm not sure that it shouldn't exist, but it should

    certainly be confined to explicitly declared OUT parameters.

     > A quick run through here should help:

    > http://en.wikipedia.org/wiki/Evaluation_strategy

     Yes, that's what I used after I wrote my first draft to make it look

    like I knew what I was talking about.

     > Caveat: It is possible to have an eager yet non-strict language. Wikipedia conflates eagerness and strictness which is unfortunate, although most existing eager languages are indeed strict. The Id programming language is an example of an eager, non-strict language.

     WP's explanation of non-strictness on that page is pathetic. BUT, I'm

    puzzled... Their definition is clear, and it matches what the first

    pageful Google results seem to be using, and their definition utterly

    precludes yours... So I'm curious. How is Id both eager and

    non-strict?

     > Wikipedia is bad at precision.

     If this is true, its accuracy is more to be bemoaned than its precision.

    Usually its clarity is worse. Especially in highly technical matters.

     > Concatenative languages do not have lambda abstractions, but you can achieve a similar result by placing a function on the stack and lifting values into it (e.g. via Factor's misnamed 'curry' function; it really should be called 'partial-apply' or similar, although that's not exactly right either).

     In a more general sense, what you're describing is passing a function

    _as_ data -- not data inside a function, but rather a function as

    data.

     > - jn

     -Wm

## John Cowan — 2010-07-21 04:33:46

    William Tanksley, Jr scripsit:

     > No; C++ allows call by reference semantics (explicitly specified, of

    > course) without being lazy at all. An early Fortran had implicit call

    > by reference, again not lazy (but, I'm told, very dangerous). I don't

    > use Perl, but I'm told it's call-by-reference.

     The default calling strategy for Fortran is and always has been call by

    reference.  The dangerous bit was an implementation, not a specification,

    error.  Buggy compilers conflated all instances of identical constants

    (thus there would be only one cell containing 5 no matter how many literal

    5s there were in the code) without realizing that literals passed as

    arguments could not be conflated in such a manner.

    Perl is technically call-by-reference, but it is usual to provide lexically

    scoped variables that are mapped to the values of the call-by-reference

    parameters, and to assign them first thing in each procedure.  The main

    exception is the comparison procedure passed to "sort", which uses

    by-reference arguments directly (always named "$a" and "$b") for speed.

    --

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

    Assent may be registered by a signature, a handshake, or a click of a computer

    mouse transmitted across the invisible ether of the Internet. Formality

    is not a requisite; any sign, symbol or action, or even willful inaction,

    as long as it is unequivocally referable to the promise, may create a contract.

           --Specht v. Netscape

## John Nowak — 2010-07-21 04:39:54

    On 2010.07.21, at 12:18 AM, William Tanksley, Jr wrote:

     > In order to pass a function to a procedure, the function has to be

    > available as data. If it's not, you can't pass it.

    >

    > Now, if your language is lazy (or non-strict) this doesn't matter; you

    > can avoid executing the function by never mentioning its parameter on

    > an execution path.

     In an eager language without first-class functions, the language implementor can offer a special 'delay' form that creates a thunk at runtime. A 'force' function can later force the computation to occur. Since the only real semantic issue with introducing 'delay' is due to strictness (e.g. 'delay (4 / 0)' would not cause an error until forced even though '4 / 0' does immediately), it's a relatively uncomplicated addition from a theoretical perspective.

     > This allows languages that don't provide higher-order functions to still be very expressive.

     You'd still need some way to parameterize functions by other functions even if functions aren't available as data at runtime. OBJ is an excellent example of how to do parameterized programming without first-class functions.

    - jn

## Don Groves — 2010-07-21 05:12:30

    On 20 Jul 2010, at 21:18, William Tanksley, Jr wrote:

     > Don Groves <dgroves@...> wrote:

    >> William Tanksley, Jr wrote:

    >>> Don Groves <dgroves@...> wrote:

    >>>>>>> "William Tanksley, Jr" <wtanksleyjr@> wrote:

    >>>>>>>> Laziness is one of the things that can't easily be imported

    >>>>>>>> to a

    >>>>>>>> concatenative language.

    >>>>  It seems to me that laziness can be implemented simply by

    >>>> encapsulating all data in functions. If a particular function

    >>>> is not called, that data is not evaluated. What am I missing?

    >

    >>> Data isn't supposed to be evaluated, of course; I think you meant

    >>> encapsulating all functions in data rather than the other way

    >>> around.

    >

    >> OK, guess I may need some hand-holding here:

    >

    > No... It's just unclear presuppositions. Thanks for making them clear

    > by asking about them.

     You're welcome and this is getting vert interesting ;-)

    First, I should explain my background. When I was at UCLA in

    the early 60s, there was no such field as computer science.

    The closest thing to it was a math class on numerical methods

    taught by a physics professor.

    I was working as a Fortran programmer though and that's how

    I came to know this stuff. I learned assembly languages by always

    printing what Fortran compilers called the "second file" which had

    the assembly code interspersed in the Fortran code. Those were

    the good old days for me...

     >> Isn't call-by-reference essentially equivalent to lazy evaluation?

    >

    > No; C++ allows call by reference semantics (explicitly specified, of

    > course) without being lazy at all. An early Fortran had implicit call

    > by reference, again not lazy (but, I'm told, very dangerous). I don't

    > use Perl, but I'm told it's call-by-reference.

     The reason Fortran's call by reference was so dangerous was that

    numerical constants were also passed by reference and hence their

    value could be changed by the called subroutine. This was lazy all

    right, a lazy implementation. Passing the address of a function which

    would yield the constant would have been far safer but, in those days,

    the programmer was expected to do most of the work. Programmer

    time was dirt cheap by comparison to machine time on an IBM 7094

    that cost $2 million 1960 dollars!

     > Wikipedia just reminded me that you're thinking of "call by name" or

    > "call by need", but those are simply ways to achieve lazy evaluation.

    >

    >> If the called function doesn't need a certain parameter during a

    >> particular call, that parameter will not be evaluated. So, parameters

    >> (data) are only evaluated when needed, i.e., they are lazy.

    >

    > That IS what lazy evaluation is, yes.

     OK, at least I've got a handle on that concept.

     >> In a call-by-value environment, It seems to me that encapsulating

    >> all data in functions yields the same effect as call-by-reference. If

    >> a parameter is not needed, its evaluating function will not be

    >> called.

    >

    > This gets confusing to me, so hold on tight... :-)

    >

    > In order to pass a function to a procedure, the function has to be

    > available as data. If it's not, you can't pass it.

     I don't understand this -- I do it all the time in my C code by using

    the

    address operator, &, and the same is easily done in Forth, et al.

    It means, of course that the called function must be more intelligent

    than is required in some languages. It must know the type values

    of its parameters. As I've read on this list in the past, it seems there

    has been a lot of research aimed at automating that very task.

    As I said, a most interesting and enlightening discussion. Thanks

    for taking part.

    don

     > Now, if your language is lazy (or non-strict) this doesn't matter; you

    > can avoid executing the function by never mentioning its parameter on

    > an execution path. This allows languages that don't provide

    > higher-order functions to still be very expressive.

    >

    >> don

    >

    > -Wm

    >

    >

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

    >

    > Yahoo! Groups Links

    >

    >

    >

## John Nowak — 2010-07-21 05:27:59

    On 2010.07.21, at 12:32 AM, William Tanksley, Jr wrote:

     > John Nowak <john@...> wrote:

    >

    >> Nope. Call-by-reference is an abomination that shouldn't exist. Lazy evaluation is unrelated.

    >

    > Heh. John, is this because CBR hypothetically allows mutation of arbitrary items? I'm not sure that it shouldn't exist, but it should certainly be confined to explicitly declared OUT parameters.

     I overstated my point. Call-by-reference is okay provided that it is not the default and that the language has sufficient support to keep things sane. Ada is a nice example of how to do it properly.

     > WP's explanation of non-strictness on that page is pathetic. BUT, I'm puzzled... Their definition is clear, and it matches what the first pageful Google results seem to be using, and their definition utterly precludes yours... So I'm curious. How is Id both eager and non-strict?

     A lazy language is prevented from evaluating more than is absolutely necessary. This is fatal to implicit parallelism; you can't kick off a parallel evaluation unless you're sure that the results of both evaluations are needed.

    Id is an implicitly parallel language, and hence lazy evaluation was not an option. An eager, strict approach is possible, but it also limits parallelism to some degree. For example, if you have multiple evaluations running in parallel and you discover that one of them is not needed, you're not allowed to abort it. On the contrary, you need to continue running it simply to see if it evaluates to an error or not. In the worst case, one of these unneeded parallel evaluations goes into an infinite loop and the entire program cannot continue as a result.

    A language that uses lenient evaluation is optimal for parallelism. It does this by both allowing speculative evaluation and by throwing out the requirement that strictness be respected. For example, the result of 'first (4/2, 4/0)' can be either '2' or an error in a lenient language. As such, it is an example of a non-deteriministic evaluation strategy (which is a downside).

    Another nice advantage of lenient languages is that you can optimize without concern for ensuring termination. For example, the rewrite rule 'first (a, b) -> a' is a valid means of optimizing a lazy or lenient language (assuming they're pure), but not a valid means for optimizing an eager language (because the second element of the tuple may be _|_).

    Here's a nice paper on lenient evaluation:

    http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.137.9885

    In addition, you may want to look at optimistic evaluation with is also non-strict and (primarily) eager. Like lenient evaluation, it allows speculative evaluation. Unlike lenient evaluation however, it is deterministic. If a speculative evaluation encounters an error, it avoids signaling it until it is determined that the result is needed. If an evaluation takes too long (meaning it may be looping) or is otherwise progressing in an undesirable fashion, it is aborted. For this reason, optimistic evaluation was seen as a way of getting better performance out of Haskell. While optimistic evaluation doesn't have the downside of non-determinstism, it brings with it additional overhead and runtime complexity compared to eager evaluation.

    Ennals and SPJ on optimistic evaluation:

    http://research.microsoft.com/en-us/um/people/simonpj/Papers/optimistic/index.htm

    I think languages of the future may well embrace lenient evaluation, although I'm less sure about optimistic evaluation. By easing the requirements around strictness, additional optimizations are possible and parallelism is easier to attain. The overhead of lenient evaluation can be eliminated by only employing it in ways that do not require additional boxing of values. As such, lenient evaluation allows for strictly better performance (no pun intended) than eager evaluation.

     >> Concatenative languages do not have lambda abstractions, but you can achieve a similar result by placing a function on the stack and lifting values into it (e.g. via Factor's misnamed 'curry' function; it really should be called 'partial-apply' or similar, although that's not exactly right either).

    >

    > In a more general sense, what you're describing is passing a function

    > _as_ data -- not data inside a function, but rather a function as

    > data.

     Correct.

    - jn

## Don Groves — 2010-07-21 05:57:50

    On 20 Jul 2010, at 21:33, John Cowan wrote:

     > William Tanksley, Jr scripsit:

    >

    >> No; C++ allows call by reference semantics (explicitly specified, of

    >> course) without being lazy at all. An early Fortran had implicit call

    >> by reference, again not lazy (but, I'm told, very dangerous). I don't

    >> use Perl, but I'm told it's call-by-reference.

    >

    > The default calling strategy for Fortran is and always has been call

    > by

    > reference.  The dangerous bit was an implementation, not a

    > specification,

    > error.  Buggy compilers conflated all instances of identical constants

    > (thus there would be only one cell containing 5 no matter how many

    > literal

    > 5s there were in the code) without realizing that literals passed as

    > arguments could not be conflated in such a manner.

     And there was also the problem of the called routine's ability to

    change the value of a constant so passed. There were some pretty

    neat obfuscations around due to this feature though...

    don

     > Perl is technically call-by-reference, but it is usual to provide

    > lexically

    > scoped variables that are mapped to the values of the call-by-

    > reference

    > parameters, and to assign them first thing in each procedure.  The

    > main

    > exception is the comparison procedure passed to "sort", which uses

    > by-reference arguments directly (always named "$a" and "$b") for

    > speed.

    >

    > --

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

    > Assent may be registered by a signature, a handshake, or a click of

    > a computer

    > mouse transmitted across the invisible ether of the Internet.

    > Formality

    > is not a requisite; any sign, symbol or action, or even willful

    > inaction,

    > as long as it is unequivocally referable to the promise, may create

    > a contract.

    >       --Specht v. Netscape

    >

    >

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

    >

    > Yahoo! Groups Links

    >

    >

    >

## Don Groves — 2010-07-21 06:06:07

    On 20 Jul 2010, at 21:32, William Tanksley, Jr wrote:

     > John Nowak <john@...> wrote:

    >> Don Groves wrote:

    >>> Isn't call-by-reference essentially equivalent to lazy evaluation?

    >> Nope. Call-by-reference is an abomination that shouldn't exist.

    >> Lazy evaluation is unrelated.

    >

    > Heh. John, is this because CBR hypothetically allows mutation of

    > arbitrary items? I'm not sure that it shouldn't exist, but it should

    > certainly be confined to explicitly declared OUT parameters.

    >

    >> A quick run through here should help:

    >> http://en.wikipedia.org/wiki/Evaluation_strategy

    >

    > Yes, that's what I used after I wrote my first draft to make it look

    > like I knew what I was talking about.

    >

    >> Caveat: It is possible to have an eager yet non-strict language.

    >> Wikipedia conflates eagerness and strictness which is unfortunate,

    >> although most existing eager languages are indeed strict. The Id

    >> programming language is an example of an eager, non-strict language.

    >

    > WP's explanation of non-strictness on that page is pathetic. BUT, I'm

    > puzzled... Their definition is clear, and it matches what the first

    > pageful Google results seem to be using, and their definition utterly

    > precludes yours... So I'm curious. How is Id both eager and

    > non-strict?

    >

    >> Wikipedia is bad at precision.

    >

    > If this is true, its accuracy is more to be bemoaned than its

    > precision.

    >

    > Usually its clarity is worse. Especially in highly technical matters.

    >

    >> Concatenative languages do not have lambda abstractions, but you

    >> can achieve a similar result by placing a function on the stack and

    >> lifting values into it (e.g. via Factor's misnamed 'curry'

    >> function; it really should be called 'partial-apply' or similar,

    >> although that's not exactly right either).

    >

    > In a more general sense, what you're describing is passing a function

    > _as_ data -- not data inside a function, but rather a function as

    > data.

     What I'm describing is passing a function as a data source.

    I feel data should be treated like any other (possibly) shared asset.

    That is, assign a semaphore to it in the guise of a function that is its

    one and only evaluator. Laziness comes along for the ride...

    don

     >

    >> - jn

    >

    > -Wm

    >

    >

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

    >

    > Yahoo! Groups Links

    >

    >

    >

## John Cowan — 2010-07-21 13:48:07

    John Nowak scripsit:

     > In an eager language without first-class functions, the language

    > implementor can offer a special 'delay' form that creates a thunk

    > at runtime. A 'force' function can later force the computation to

    > occur. Since the only real semantic issue with introducing 'delay'

    > is due to strictness (e.g. 'delay (4 / 0)' would not cause an error

    > until forced even though '4 / 0' does immediately), it's a relatively

    > uncomplicated addition from a theoretical perspective.

     Note, however, that delay and force don't play well with tail recursion:

    see SRFI 45 <http://srfi.schemers.org/srfi-45/srfi-45.html> for a

    proposed resolution.

    --

    If I read "upcoming" in [the newspaper]              John Cowan

    once more, I will be downcoming                      http://www.ccil.org/~cowan

    and somebody will be outgoing.                       cowan@...

## pml060912 — 2010-07-22 15:55:59

    --- In concatenative@yahoogroups.com, Don Groves <dgroves@...> wrote:

     >

    > On 20 Jul 2010, at 21:18, William Tanksley, Jr wrote:

    >

    > > Don Groves <dgroves@...> wrote:

     .

    .

    .

     > >> In a call-by-value environment, It seems to me that encapsulating

    > >> all data in functions yields the same effect as call-by-reference. If

    > >> a parameter is not needed, its evaluating function will not be

    > >> called.

    > >

    > > This gets confusing to me, so hold on tight... :-)

    > >

    > > In order to pass a function to a procedure, the function has to be

    > > available as data. If it's not, you can't pass it.

    >

    > I don't understand this -- I do it all the time in my C code by using

    > the

    > address operator, &, and the same is easily done in Forth, et al.

     That's pretty much the same indirection approach I use in Furphy (see http://users.beagle.com.au/peterl/furphy.html), to achieve the same effect with a workaround even when what actually happens is done eagerly. I even describe it there with an analogy to what you are thinking of in C:-

    Conditional code is mostly achieved by IF and a complementary pair of things, freezing and thawing. This is a bit like using indirection in C to pass parameters by name instead of the default by value. The analogy here is that IF does eager evaluation, and freezing and thawing change the behaviour to lazy evaluation. IF has this behaviour, using Forth documenting standards: (  true/false_flag  true_option  false_option  ---  result  ).

    FREEZE and THAW behave like an anonymous label (if that isn't a contradiction in terms - it really returns early and pushes a re-entry address to the stack) and a dynamic subroutine call, different from the Forth keyword EXECUTE that it resembles. Typically, you would put FREEZE at the beginning of each keyword that you might want to select with IF and then you would use THAW on whichever one got chosen, like this:-

    FREEZE TRUE_STUFF TRUE_OPTION

    FREEZE FALSE_STUFF FALSE_OPTION

    GET_FLAG TRUE_OPTION FALSE_OPTION IF THAW DEMO

    Later on I describe some syntactic sugar to make coding and using the indirection easier, too. P.M.Lawrence.

## Don Groves — 2010-07-22 22:33:04

    >

    > .

    >>>> In a call-by-value environment, It seems to me that encapsulating

    >>>> all data in functions yields the same effect as call-by-

    >>>> reference. If

    >>>> a parameter is not needed, its evaluating function will not be

    >>>> called.

    >>>

    >>> This gets confusing to me, so hold on tight... :-)

    >>>

    >>> In order to pass a function to a procedure, the function has to be

    >>> available as data. If it's not, you can't pass it.

    >>

    >> I don't understand this -- I do it all the time in my C code by using

    >> the

    >> address operator, &, and the same is easily done in Forth, et al.

    >

    > That's pretty much the same indirection approach I use in Furphy

    > (see http://users.beagle.com.au/peterl/furphy.html), to achieve the

    > same effect with a workaround even when what actually happens is

    > done eagerly. I even describe it there with an analogy to what you

    > are thinking of in C:-

    >

    > Conditional code is mostly achieved by IF and a complementary pair

    > of things, freezing and thawing. This is a bit like using

    > indirection in C to pass parameters by name instead of the default

    > by value. The analogy here is that IF does eager evaluation, and

    > freezing and thawing change the behaviour to lazy evaluation. IF has

    > this behaviour, using Forth documenting standards: (  true/

    > false_flag  true_option  false_option  ---  result  ).

    >

    > FREEZE and THAW behave like an anonymous label (if that isn't a

    > contradiction in terms - it really returns early and pushes a re-

    > entry address to the stack) and a dynamic subroutine call, different

    > from the Forth keyword EXECUTE that it resembles. Typically, you

    > would put FREEZE at the beginning of each keyword that you might

    > want to select with IF and then you would use THAW on whichever one

    > got chosen, like this:-

    >

    > FREEZE TRUE_STUFF TRUE_OPTION

    >

    > FREEZE FALSE_STUFF FALSE_OPTION

    >

    > GET_FLAG TRUE_OPTION FALSE_OPTION IF THAW DEMO

    >

    > Later on I describe some syntactic sugar to make coding and using

    > the indirection easier, too. P.M.Lawrence.

     Thanks. Do you feel your approach is equivalent to lazy evaluation?

    don

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

    >

    > Yahoo! Groups Links

    >

    >

    >

## pml060912 — 2010-07-23 09:56:10

    --- In concatenative@yahoogroups.com, Don Groves <dgroves@...> wrote:

     >

    > >

    > > .

    > >>>> In a call-by-value environment, It seems to me that encapsulating

    > >>>> all data in functions yields the same effect as call-by-

    > >>>> reference. If

    > >>>> a parameter is not needed, its evaluating function will not be

    > >>>> called.

    > >>>

    > >>> This gets confusing to me, so hold on tight... :-)

    > >>>

    > >>> In order to pass a function to a procedure, the function has to be

    > >>> available as data. If it's not, you can't pass it.

    > >>

    > >> I don't understand this -- I do it all the time in my C code by using

    > >> the

    > >> address operator, &, and the same is easily done in Forth, et al.

    > >

    > > That's pretty much the same indirection approach I use in Furphy

    > > (see http://users.beagle.com.au/peterl/furphy.html), to achieve the

    > > same effect with a workaround even when what actually happens is

    > > done eagerly. I even describe it there with an analogy to what you

    > > are thinking of in C:-

    > >

    > > Conditional code is mostly achieved by IF and a complementary pair

    > > of things, freezing and thawing. This is a bit like using

    > > indirection in C to pass parameters by name instead of the default

    > > by value. The analogy here is that IF does eager evaluation, and

    > > freezing and thawing change the behaviour to lazy evaluation. IF has

    > > this behaviour, using Forth documenting standards: (  true/

    > > false_flag  true_option  false_option  ---  result  ).

    > >

    > > FREEZE and THAW behave like an anonymous label (if that isn't a

    > > contradiction in terms - it really returns early and pushes a re-

    > > entry address to the stack) and a dynamic subroutine call, different

    > > from the Forth keyword EXECUTE that it resembles. Typically, you

    > > would put FREEZE at the beginning of each keyword that you might

    > > want to select with IF and then you would use THAW on whichever one

    > > got chosen, like this:-

    > >

    > > FREEZE TRUE_STUFF TRUE_OPTION

    > >

    > > FREEZE FALSE_STUFF FALSE_OPTION

    > >

    > > GET_FLAG TRUE_OPTION FALSE_OPTION IF THAW DEMO

    > >

    > > Later on I describe some syntactic sugar to make coding and using

    > > the indirection easier, too. P.M.Lawrence.

    >

    > Thanks. Do you feel your approach is equivalent to lazy evaluation?

     We had that discussion earlier, I think actually on this thread. I feel it works out like this:-

    - From the program's point of view, it is equivalent to lazy evaluation, because the behaviour it delivers is the same.

    - From the programmer's point of view, it is not, because he or she has to do something explicit to achieve it. Before the syntactic sugar, quite a bit is needed to get things like recursion and loops, but even though that cuts it down it still doesn't eliminate it.

    Taking all in all, I decided to document it as "change the behaviour to lazy evaluation", not to call it lazy evaluation as such. P.M.Lawrence.

## Don Groves — 2010-07-23 21:29:37

    On 23 Jul 2010, at 02:56, pml060912 wrote:

     > --- In concatenative@yahoogroups.com, Don Groves <dgroves@...> wrote:

    >>

    >>>

    >>> .

    >>>>>> In a call-by-value environment, It seems to me that encapsulating

    >>>>>> all data in functions yields the same effect as call-by-

    >>>>>> reference. If

    >>>>>> a parameter is not needed, its evaluating function will not be

    >>>>>> called.

    >>>>>

    >>>>> This gets confusing to me, so hold on tight... :-)

    >>>>>

    >>>>> In order to pass a function to a procedure, the function has to be

    >>>>> available as data. If it's not, you can't pass it.

    >>>>

    >>>> I don't understand this -- I do it all the time in my C code by

    >>>> using

    >>>> the

    >>>> address operator, &, and the same is easily done in Forth, et al.

    >>>

    >>> That's pretty much the same indirection approach I use in Furphy

    >>> (see http://users.beagle.com.au/peterl/furphy.html), to achieve the

    >>> same effect with a workaround even when what actually happens is

    >>> done eagerly. I even describe it there with an analogy to what you

    >>> are thinking of in C:-

    >>>

    >>> Conditional code is mostly achieved by IF and a complementary pair

    >>> of things, freezing and thawing. This is a bit like using

    >>> indirection in C to pass parameters by name instead of the default

    >>> by value. The analogy here is that IF does eager evaluation, and

    >>> freezing and thawing change the behaviour to lazy evaluation. IF has

    >>> this behaviour, using Forth documenting standards: (  true/

    >>> false_flag  true_option  false_option  ---  result  ).

    >>>

    >>> FREEZE and THAW behave like an anonymous label (if that isn't a

    >>> contradiction in terms - it really returns early and pushes a re-

    >>> entry address to the stack) and a dynamic subroutine call, different

    >>> from the Forth keyword EXECUTE that it resembles. Typically, you

    >>> would put FREEZE at the beginning of each keyword that you might

    >>> want to select with IF and then you would use THAW on whichever one

    >>> got chosen, like this:-

    >>>

    >>> FREEZE TRUE_STUFF TRUE_OPTION

    >>>

    >>> FREEZE FALSE_STUFF FALSE_OPTION

    >>>

    >>> GET_FLAG TRUE_OPTION FALSE_OPTION IF THAW DEMO

    >>>

    >>> Later on I describe some syntactic sugar to make coding and using

    >>> the indirection easier, too. P.M.Lawrence.

    >>

    >> Thanks. Do you feel your approach is equivalent to lazy evaluation?

    >

    > We had that discussion earlier, I think actually on this thread. I

    > feel it works out like this:-

    >

    > - From the program's point of view, it is equivalent to lazy

    > evaluation, because the behaviour it delivers is the same.

    >

    > - From the programmer's point of view, it is not, because he or she

    > has to do something explicit to achieve it. Before the syntactic

    > sugar, quite a bit is needed to get things like recursion and loops,

    > but even though that cuts it down it still doesn't eliminate it.

    >

    > Taking all in all, I decided to document it as "change the behaviour

    > to lazy evaluation", not to call it lazy evaluation as such.

    > P.M.Lawrence.

    >

     But if that behavior is built into the language, why does an

    application programmer have to do anything explicit?

    don

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

    >

    > Yahoo! Groups Links

    >

    >

    >

## pml060912 — 2010-07-24 11:04:51

    --- In concatenative@yahoogroups.com, Don Groves <dgroves@...> wrote:

     >

    > On 23 Jul 2010, at 02:56, pml060912 wrote:

    >

    > > --- In concatenative@yahoogroups.com, Don Groves <dgroves@> wrote:

     .

    .

    .

     > >> Thanks. Do you feel your approach is equivalent to lazy evaluation?

    > >

    > > We had that discussion earlier, I think actually on this thread. I

    > > feel it works out like this:-

    > >

    > > - From the program's point of view, it is equivalent to lazy

    > > evaluation, because the behaviour it delivers is the same.

    > >

    > > - From the programmer's point of view, it is not, because he or she

    > > has to do something explicit to achieve it. Before the syntactic

    > > sugar, quite a bit is needed to get things like recursion and loops,

    > > but even though that cuts it down it still doesn't eliminate it.

    > >

    > > Taking all in all, I decided to document it as "change the behaviour

    > > to lazy evaluation", not to call it lazy evaluation as such.

    > > P.M.Lawrence.

    > >

    >

    > But if that behavior is built into the language, why does an

    > application programmer have to do anything explicit?

     It's not built into the language, in that sense, any more than the fact that a gear lever and clutch pedal in a car make it have an automatic transmission. Rather, there are keywords the programmer can use to get the indirection that gives lazy behaviour to the code built with them even though those indirection keywords work eagerly - just as the car can change gears, but only when the driver works the controls for that. It's not enough to code branches with IF (say), the programmer also needs to put FREEZE into keywords for each branch (or use the [ ] pair in inline code) and then use THAW to make use of whatever was frozen (maybe with some of that hidden in yet other keywords). IF by itself only delivers eager behaviour. The programmer has to make explicit use of the indirection to achieve lazy behaviour, since the default is eager. P.M.Lawrence.

## Don Groves — 2010-07-24 21:01:55

    On 24 Jul 2010, at 04:04, pml060912 wrote:

     > --- In concatenative@yahoogroups.com, Don Groves <dgroves@...> wrote:

    >>

    >> On 23 Jul 2010, at 02:56, pml060912 wrote:

    >>

    >>> --- In concatenative@yahoogroups.com, Don Groves <dgroves@> wrote:

    > .

    > .

    > .

    >>>> Thanks. Do you feel your approach is equivalent to lazy evaluation?

    >>>

    >>> We had that discussion earlier, I think actually on this thread. I

    >>> feel it works out like this:-

    >>>

    >>> - From the program's point of view, it is equivalent to lazy

    >>> evaluation, because the behaviour it delivers is the same.

    >>>

    >>> - From the programmer's point of view, it is not, because he or she

    >>> has to do something explicit to achieve it. Before the syntactic

    >>> sugar, quite a bit is needed to get things like recursion and loops,

    >>> but even though that cuts it down it still doesn't eliminate it.

    >>>

    >>> Taking all in all, I decided to document it as "change the behaviour

    >>> to lazy evaluation", not to call it lazy evaluation as such.

    >>> P.M.Lawrence.

    >>>

    >>

    >> But if that behavior is built into the language, why does an

    >> application programmer have to do anything explicit?

    >

    > It's not built into the language, in that sense, any more than the

    > fact that a gear lever and clutch pedal in a car make it have an

    > automatic transmission. Rather, there are keywords the programmer

    > can use to get the indirection that gives lazy behaviour to the code

    > built with them even though those indirection keywords work eagerly

    > - just as the car can change gears, but only when the driver works

    > the controls for that. It's not enough to code branches with IF

    > (say), the programmer also needs to put FREEZE into keywords for

    > each branch (or use the [ ] pair in inline code) and then use THAW

    > to make use of whatever was frozen (maybe with some of that hidden

    > in yet other keywords). IF by itself only delivers eager behaviour.

    > The programmer has to make explicit use of the indirection to

    > achieve lazy behaviour, since the default is eager. P.M.Lawrence.

     Now I've got it, thanks.

    don

     >

    >

    >

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

    >

    > Yahoo! Groups Links

    >

    >

    >

## William Tanksley, Jr — 2010-07-25 14:45:53

    John Nowak <john@...> wrote:

     > You'd still need some way to parameterize functions

    > by other functions even if functions aren't available as

    > data at runtime. OBJ is an excellent example of how

    > to do parameterized programming without first-class

    > functions.

     Obviously, OBJ was invented long before Google searches :-). It took

    me a long time to find a link that actually had anything to do with

    the language. A better search string is "OBJ3". Unfortunately, I'm

    still clueless; none of the available references explain what you

    meant.

    I'm curious... How is OBJ an excellent example of that? It sounds like

    a useful property!

     > - jn

     -Wm

## John Nowak — 2010-07-25 22:29:14

    On 2010.07.25, at 10:45 AM, William Tanksley, Jr wrote:

     > John Nowak <john@...> wrote:

    >

    >> You'd still need some way to parameterize functions

    >> by other functions even if functions aren't available as

    >> data at runtime. OBJ is an excellent example of how

    >> to do parameterized programming without first-class

    >> functions.

    >

    > I'm curious... How is OBJ an excellent example of that? It sounds like

    > a useful property!

     It's just parameterized modules a la Ada or ML. The values of the parameters can be resolved statically; module instantiation essentially happens before the program is run.

    This should help:

    http://cseweb.ucsd.edu/~goguen/pps/utyop.ps

    - jn