From: "stevan apter" <sa@...>
>i have a question about the unary combinator.Yes -- I don't blame you. It's ugly and non-optimal.
But when you know what you're doing, it can be
useful.
>i'm not sure how to phrase my question. i suppose itIt's neither good nor bad; it's just odd.
>boils down to whether this is good behavior for a
>primitive, returning just part of a result. (or
>perhaps not, since x / y loses information too.)
There are a lot of operators in Joy that I class as
odd; in essence, anything with a number in its name
is not optimal. That doesn't mean, though, that
making an identical function which takes the number
as a parameter would fix the problem.
>the programmer who uses unary (and similarNo doubt.
>combinators) had better know how many results its
>program argument will return: if just one, he'll
>get the whole result; if more, he'll get
>just the last part.
-Billy
it's worse (if that's the right word for it) than i thought -
[1 2 3][dup]map
[1 2 3]
which means, i suppose, that you need to design [p] knowing
that it will be mapped:
[1 2 3][dup [] cons cons] map
[[1 1][2 2][3 3]]
i'm not suggesting that this is wrong, just noting that my
expectations were confounded.
--
From: "stevan apter" <sa@...>
>i have a question about the unary combinator.Yes -- I don't blame you. It's ugly and non-optimal.
But when you know what you're doing, it can be
useful.
>i'm not sure how to phrase my question. i suppose itIt's neither good nor bad; it's just odd.
>boils down to whether this is good behavior for a
>primitive, returning just part of a result. (or
>perhaps not, since x / y loses information too.)
There are a lot of operators in Joy that I class as
odd; in essence, anything with a number in its name
is not optimal. That doesn't mean, though, that
making an identical function which takes the number
as a parameter would fix the problem.
>the programmer who uses unary (and similarNo doubt.
>combinators) had better know how many results its
>program argument will return: if just one, he'll
>get the whole result; if more, he'll get
>just the last part.
-Billy
To unsubscribe from this group, send an email to:
concatenative-unsubscribe@egroups.com
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
From: sa@...
>which means, i suppose, that you need to designWhat were your expectations?
>[p] knowing that it will be mapped:
> [1 2 3][dup [] cons cons] map
> [[1 1][2 2][3 3]]
>i'm not suggesting that this is wrong, just noting that my
>expectations were confounded.
I'm guessing that you would expect
[1 2 3] [dup] map
to return
[[1 1][2 2][3 3]].
Correct? This is reasonable and quite workable, IMO;
it's what I would expect as well. It's just a bit hard
to work with using Joy as it stands, but it's easy for
cK to handle.
-Billy
wtanksleyjr@... writes:
> From: sa@...More generally I guess all combinators could push their temporary
> >which means, i suppose, that you need to design
> >[p] knowing that it will be mapped:
> > [1 2 3][dup [] cons cons] map
> > [[1 1][2 2][3 3]]
>
> >i'm not suggesting that this is wrong, just noting that my
> >expectations were confounded.
>
> What were your expectations?
>
> I'm guessing that you would expect
> [1 2 3] [dup] map
> to return
> [[1 1][2 2][3 3]].
>
> Correct? This is reasonable and quite workable, IMO;
> it's what I would expect as well. It's just a bit hard
> to work with using Joy as it stands, but it's easy for
> cK to handle.
stacks as lists if their length was greater than intended
(expected). However, this would place the responsibility of cleaning
temporary stacks onto the user... possibly not a bad thing.
Nick.
From: Nick Forde <nickf@...>
>More generally I guess all combinators could pushPossibly. However, here's another possibility:
>their temporary stacks as lists if their length
>was greater than intended (expected). However,
>this would place the responsibility of cleaning
>temporary stacks onto the user... possibly not a
>bad thing.
4 5 6 [1 2 3] [+] map
What happens?
Are the cases parallel?
> Nick.-Billy
no no - i'm not suggesting any change at all in the behavior of joy
or in the primitives as they stand. i'm simply noting (in a public
way) the "dangerous curves" of the language as i'm learning to use
it.
for example, i tend to think of 'map' as taking a unary function and
applying it to each item of a list. but that's misleading, as you can
see from
2 [3 4 5] [+] map
2 [5 6 7]
i hope you would agree that it's less than desireable to present the
definition of a language (especially a functional one) in operational
terms, e.g. "map takes a program p, a list l, and the remainder of the
stack s, then loops over elements l[i], computing the result-stack t
of s,l[i],p, takes the last element of t and appends it to the output
list o,..." etc. but how else to nail down the precise behavior? not,
i think, with standard stack notation (although perhaps i'm not fully
aware of the conventions people have evolved to deal with this kind of
thing.)
i'm getting the feeling that the problem (if it is one) is the result
of having these two degrees of freedom: an operation can (will) eat
as much of the stack as it needs to do its thing, and an operation
can return more than one result. when you throw in the ability to
create arbitrarily complex constructions through concatenation, you
can't just look at a program in isolation and immediately understand
its behavior on arbitrary stacks, or under the control of arbitrary
combinators. but then, i guess that's just the flip side of the power
of joy.
so, in answer to your question billy, no, i don't think it is easy
to tame this kind of thing. dup always returns 2 things, + always
eats two things, and map (for example) can't know these sorts of
facts about the program it's applying.
--
Nick Forde
<nickf@cadenc To: concatenative@yahoogroups.com
e.com> cc:
Subject: Re: Re: [stack] Fw: the unary combinator
05/21/03
12:39 PM
Please
respond to
concatenative
wtanksleyjr@... writes:
> From: sa@...More generally I guess all combinators could push their temporary
> >which means, i suppose, that you need to design
> >[p] knowing that it will be mapped:
> > [1 2 3][dup [] cons cons] map
> > [[1 1][2 2][3 3]]
>
> >i'm not suggesting that this is wrong, just noting that my
> >expectations were confounded.
>
> What were your expectations?
>
> I'm guessing that you would expect
> [1 2 3] [dup] map
> to return
> [[1 1][2 2][3 3]].
>
> Correct? This is reasonable and quite workable, IMO;
> it's what I would expect as well. It's just a bit hard
> to work with using Joy as it stands, but it's easy for
> cK to handle.
stacks as lists if their length was greater than intended
(expected). However, this would place the responsibility of cleaning
temporary stacks onto the user... possibly not a bad thing.
Nick.
To unsubscribe from this group, send an email to:
concatenative-unsubscribe@egroups.com
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
Nick Forde scripsit:
> More generally I guess all combinators could push their temporaryIn fact both the C and the Scheme implementations use a list representation
> stacks as lists if their length was greater than intended
> (expected). However, this would place the responsibility of cleaning
> temporary stacks onto the user... possibly not a bad thing.
for the stack.
--
And through this revolting graveyard of the universe the muffled, maddening
beating of drums, and thin, monotonous whine of blasphemous flutes from
inconceivable, unlighted chambers beyond Time; the detestable pounding
and piping whereunto dance slowly, awkwardly, and absurdly the gigantic
tenebrous ultimate gods -- the blind, voiceless, mindless gargoyles whose soul
is Nyarlathotep. (Lovecraft) John Cowan|jcowan@...|ccil.org/~cowan
wtanksleyjr@... scripsit:
> Possibly. However, here's another possibility:The reference implementation says the stack is:
>
> 4 5 6 [1 2 3] [+] map
>
> What happens?
[7 8 9] 6 5 4
(that's from top to bottom, of course). IOW only the 6 is ever used,
because the stack is reset between each invocation of +.
Joy.ss 0.4 has a bug that makes it output the top value incorrectly,
but the structure of the stack is the same.
--
You are a child of the universe no less John Cowan
than the trees and all other acyclic http://www.reutershealth.com
graphs; you have a right to be here. http://www.ccil.org/~cowan
--DeXiderata by Sean McGrath jcowan@...
On Wed, 21 May 2003 sa@... wrote:
> for example, i tend to think of 'map' as taking a unary function andIndeed, that is the "normal"/"standard"/"conventional" view and
> applying it to each item of a list.
definition. Most (all?) other languages would define it that way.
In most (all?) other languages a function only returns one value,
that is what "function" means. I think you will agree in these
cases Joy's map does exactly the right thing. This includes case
where the quotation is any of the following:
[succ] [dup *] [[] cons] [dup [] cons cons]
But what about binary operators used with map? One attitude would
be to forbid it outright. That is what most (all?) other languages
would _have_ to do because the list elements are singletons. In Joy
there is another possibility: take the extra element from the stack.
That is a non-trivial extension of the usual conception of map, and
it may or may not be useful. But it also needs some decision as to
what to do with the extra element: will it be available for the
other elements in the list?
I concluded that binary, ternary .. operators should be allowed
because such an extension is indeed useful. I also concluded that
the "extra" element should not be consumed but remain available.
I present two arguments:
1. Efficiency. Suppose we have a very very long list of numbers,
"VVLLN". We want to multiply each by, say, 42. Multiplication is binary,
multiplication by a constant is unary, so that is fine. Suppose VVLLN is
already on the stack, to map it we write
[42 *] map
That is correct. But note that 42 gets pushed very very many times
because VVLLN is very very long. We could save those pushes by
allowing map to take binary operators and writing instead one of the
following:
[42] dip [*] map popd
42 swap [*] map popd
So we have a small constant overhead because of the dip or swap,
and because of the popd, but it is worth it for long lists.
(The final popd is needed to remove the 42 when all is done.)
2. Further flexibility: Suppose you have a number N on the stack,
and you want a list of a) its sucessor, b) its square, c) its
factorial, d) twice its fib, ... A very natural solution in Joy is
[ [succ] [dup *] [fact] [fib 2 *] ... ] [i] map popd
Now, the i combinator is indeed unary, as the "standard" conception
of map would require, but here it is made to work on unary
functions which all require the same further value N. But that
value is precisely the number on the stack, below the list of
quotations. So map should again not consume items below the list.
One might argue that the map combinator used with binary
operators should do the final popd automatically, and when
used with a ternary operator it should do two popd's and so on.
Moreover, when map is used with a combinator quotation such
as [i] it should then make its automatic actions of popd's
depend on the arity of the quoted functions [succ] [fact] ..
But these arities need not be the same - so should the
number of automatic popd's be the maximum or the minimum of
the arities? And is the reader of the program supposed to
go through the possibly long list of quotations to find out
how many popd's Joy will execute automatically? No, better
none at all, and let the pogrammer say it explicitly.
[..]
> i hope you would agree that it's less than desireable to present theOperational explanations often work well psychologically: people
> definition of a language (especially a functional one) in operational
> terms, e.g. "map takes a program p, a list l, and the remainder of the
> stack s, then loops over elements l[i], computing the result-stack t
> of s,l[i],p, takes the last element of t and appends it to the output
> list o,..." etc. but how else to nail down the precise behavior? not,
> i think, with standard stack notation (although perhaps i'm not fully
> aware of the conventions people have evolved to deal with this kind of
> thing.)
understand them. A non-operational definition in denotational
semantics is much harder psychologically, but especially for
functional languages not too complex. An implementation of a functional
language such as Joy in a good standard functions language
is just about identical with the denotational definition.
> i'm getting the feeling that the problem (if it is one) is the resultI have not addressed the multiple result "problem", I know. I'm not
> of having these two degrees of freedom: an operation can (will) eat
> as much of the stack as it needs to do its thing, and an operation
> can return more than one result.
at all sure it is a problem. But here is a related example:
[1 2 3] [[dup] [dup dup dup] [] [+] [+ *]] [infra] map
If your expectation of what this should do coincides with what
Joy in fact does, then Joy's map combinator does seem right,
doesn't it ?
[..]
Thank you all for the discusssion.
- Manfred
----- Original Message -----
From: <phimvt@...>
>
> I concluded that binary, ternary .. operators should be allowed
> because such an extension is indeed useful. I also concluded that
> the "extra" element should not be consumed but remain available.
> I present two arguments:
>
> 1. Efficiency. Suppose we have a very very long list of numbers,
> "VVLLN". We want to multiply each by, say, 42. Multiplication is binary,
> multiplication by a constant is unary, so that is fine. Suppose VVLLN is
> already on the stack, to map it we write
> [42 *] map
> That is correct. But note that 42 gets pushed very very many times
> because VVLLN is very very long. We could save those pushes by
> allowing map to take binary operators and writing instead one of the
> following:
> [42] dip [*] map popd
> 42 swap [*] map popd
> So we have a small constant overhead because of the dip or swap,
> and because of the popd, but it is worth it for long lists.
> (The final popd is needed to remove the 42 when all is done.)
this is persuasive. i will note that extending primitives like *
to general lists would make this a less compelling argument, since
vvlln 42 *
would leave a list result on the stack. i think map should
continue to work as it does, and so 42 vvlln [*] map would remain
available as an efficient alternative to vvlln [42 *] map, but
where the program to be mapped has the property of atomic extension,
the programmer can avoid the entire issue by applying it directly
to the list operand. e.g. [42 * 3 + neg] is atomic, so one can
simply write vvlln [42 * 3 + neg] i.
in general, i think your arguments for the current behavior are
compelling. but then, i wasn't complaining - just noting that
'map', 'unary', and similar combinators were "deeper" than i had
assumed. in other words, it's a documentation problem. once
the behavior is understood, its rightness is apparent.