askagain == "linrec" explainplease [ linrecexlained ] [ ] [askagain] ifte

cpcogan — 2004-08-10 22:34:59

Hi,
I'm a Joy newbie, implementing Joy in Visual Basic .NET, but I'm
confused about linrec.

The help for it says:

[P] [T] [R1] [R2]
Executes P. If that yields true, executes T. Else executes R1,
recurses, executes R2.

However I can't find an implementation except in tcl (yes, tcl, by
Salvatore Sanfilippo, at: http://wiki.tcl.tk/10870), and I'm not sure
it's correct.

When it recurses, does linrec push the parms back on the stack first?
Or is R1 supposed to supply a new set of four? I'm guessing that all
four of the starting quoted programs should be made available to the
recursion, so I'd further guess that they should be (at least
virtually) pushed back on the stack for the recursion.

Is this correct?

Salvatore seems to be bunching all four parms into a new list before
doing the recursion. That doesn't seem right to me because they were
separately stacked quoted programs before the initial call.

That is, it doesn't seem to fit the description of linrec above (even
though it looks like a useful function in it's own right).

By the way, has anyone any comments on Salvatore's (highly) local
variables? (Actually, they are more like Prolog variables than they
are like regular variables, because their value doesn't change within
a scope, unless one re-captures data for them.)

They look okay to me; he does restrict them so they won't change the
semantics of a function as far as the outside world is concerned. I'm
not sure yet how useful they are, but I'd think they would be of some
use in cases where the stack manipulations become a little hairy. His
mechanism for capturing them seems especially nice, because of the
minimal coding overhead.

He just matches a parenthesized "list" of the variables with the
stack, so that, for example, ($B $A) captures the top two items on
the stack ($A gets the first one, $B gets the second). Then, as long
as they are used at the same level as the code that captures them
(which excludes nesting them in a list), one is free to use them to
push the same values back on the stack as needed. This reduces the
need for all of the stack operations, which I think should make the
code a little smoother to write and read and get correct.

Finally, many thanks to whoever (no name is given) made the Win32
version and uploaded it to the files section. I will be using it a
lot, I expect, to ensure that my implementation of things is correct
(I want to stick close to the "official" version, at least initially,
and unless I find good reasons to change things (for my own use)).

--Chris C.

Slava Pestov — 2004-08-10 23:11:20

cpcogan wrote:
> Hi,
> I'm a Joy newbie, implementing Joy in Visual Basic .NET,

Please post the code when you're done :)

> The help for it says:
>
> [P] [T] [R1] [R2]
> Executes P. If that yields true, executes T. Else executes R1,
> recurses, executes R2.
>
> However I can't find an implementation except in tcl (yes, tcl, by
> Salvatore Sanfilippo, at: http://wiki.tcl.tk/10870), and I'm not sure
> it's correct.

The C implementation of Joy includes this combinator, coded as a C
primitive.

Slava

phimvt@lurac.latrobe.edu.au — 2004-08-11 07:13:52

On Tue, 10 Aug 2004, cpcogan wrote:

> Hi,
> I'm a Joy newbie, implementing Joy in Visual Basic .NET, but I'm
> confused about linrec.
>
> The help for it says:
>
> [P] [T] [R1] [R2]
> Executes P. If that yields true, executes T. Else executes R1,
> recurses, executes R2.
>
> However I can't find an implementation except in tcl (yes, tcl, by
> Salvatore Sanfilippo, at: http://wiki.tcl.tk/10870), and I'm not sure
> it's correct.
>
> When it recurses, does linrec push the parms back on the stack first?

It is as if linrec pushed them back first, but an
implementation might be able to avoid this.

> Or is R1 supposed to supply a new set of four? I'm guessing that all
> four of the starting quoted programs should be made available to the
> recursion, so I'd further guess that they should be (at least
> virtually) pushed back on the stack for the recursion.

Yes, virtually is a good way to express it.
The C-program which is the implementation has essentially
two functions to handle this:

void linrec-aux() (* "auxiliary" *)
{
Do the test P,
if that yields true, do T,
else do R1, call linrec-aux, do R2 (* no new params *)
}

void linrec() (* called when "linrec" is seen *)
{
save the top four parameters somewhere where linrec-aux can see them.
(* they are now no longer on the stack *)
call linrec-aux
delete the saved four parameters from where they were saved
}

The whole idea of having the two functions, (one to save
the params, the other to recurse as necessary) is to avoid
copying the params for every recursive call.

Hope this helps

- Manfred

P.S. It looks as though I missed an important concatenative
language in the files section - my apologies. Is the author
willing to write a section for the joint paper?

Sorry,I am too tired for today to do any more.
- M.

ccogan@cox.net — 2004-08-11 14:35:40

<snip>
Manfred says:
> void linrec-aux() (* "auxiliary" *)
> {
> Do the test P,
> if that yields true, do T,
> else do R1, call linrec-aux, do R2 (* no new params *)
> }
>
> void linrec() (* called when "linrec" is seen *)
> {
> save the top four parameters somewhere where linrec-aux can see them.
> (* they are now no longer on the stack *)
> call linrec-aux
> delete the saved four parameters from where they were saved
> }
>
> The whole idea of having the two functions, (one to save
> the params, the other to recurse as necessary) is to avoid
> copying the params for every recursive call.
>
> Hope this helps

Yes. Thanks, that's all I need.

cpcogan — 2004-08-13 15:16:49

On linrec:

> The C implementation of Joy includes this combinator, coded as a C
> primitive.
>
> Slava

You're right, but I couldn't find it. I must have had my search set
on "whole word only," so that, without the trailing underbar, it
wouldn't match.

Thanks for helping clear that up (I was almost sure it had to be
there).
--Chris