Re: [stack] Definitions at run-time
phimvt@lurac.latrobe.edu.au — 2005-03-11 07:32:42
On Thu, 10 Mar 2005, Ivan Tomac wrote:
> For some strange reason some of the recent posts to this message board
> made me dig through the archives and re-read some of the old posts as
> well as go through most of the papers on Joy again.
>
> I've noticed one thing that I haven't seen earlier that just doesn't
> seem to add up. On the "Further Frequently Asked Questions about Joy"
> page (http://www.latrobe.edu.au/philosophy/phimvt/joy/faq1.html) Manfred
> talks about the reasons why having defining words avaliable at run-time
> is a bad idea. The reason he states in the end is one relating to
> creation of variables that act the same way as they would in imperative
> languages.
>
> I have one question and one (obvious) observation: 1) Wouldn't this
> only be a problem with dynamically scoped languages? If Joy was
> lexically scoped this wouldn't be an issue.
Early Lisps were dynamically scoped, but since Landin's ISWIM both
Scheme and Common Lisp are statically scoped, and so is Joy. All of
them are dynamically typed: type checking occurs at run time. In Scheme
and Common Lisp the static scoping is extensive: there are the global
definitions of functions, the names of the formal parameters, LET
expressions, lambda variables (and variables for assignment). With all
these the scoping is an intricate affair due to the possible nesting. So
the symbol table management becomes rather complex. In Joy there are
just the global definitions, including those in HIDE's and MODULE's, and
all the other things don't occur. So it is all very simple. For all
these statically scoped languages a symbol means what it meant when the
program started running, and in the case of complex nesting in Scheme or
Common Lisp a symbol means what the enclosing scopes defined it to mean.
This ignores macros in Scheme and Common Lisp. However, I do believe that
some of the macro facilities available change matters somewhat. But I do
not understand them well enough to really tell. Google "Oleg Scheme" for
some wonderful stuff.
> 2) The imperative notion of variables can be simulated with files as
> well. Furthermore the whole concept of binding names to values and
> functions is analogous to concepts of filesystems and databases.
I think you are might be right here. But consider this:
Assume the definition: DEFINE foo == 111 . (Note the space after the
number - without it the scanner expects digits after the decimal point.)
At runtime, put the string "DEFINE foo == 222 ." on the stack, write that
string to a file, include that file, finally do "foo put.". All this in
the same run. What do you get? 222 or 111 ? You get 111, because you are
still in the same run. The new definition will only be read when the Joy
interpreter is ready to read something, after it has executed the code for
the current run. For the next run the included file will have been
processed, of course, and foo will mean 222. And all this is how it
should be, I think.
Maybe John Cowan has something to say on this topic.
- Manfred
Ivan Tomac — 2005-03-12 12:27:09
--- In
concatenative@yahoogroups.com, phimvt@l... wrote:
> On Thu, 10 Mar 2005, Ivan Tomac wrote:
> > I've noticed one thing that I haven't seen earlier that just doesn't
> > seem to add up. On the "Further Frequently Asked Questions about Joy"
> > page (http://www.latrobe.edu.au/philosophy/phimvt/joy/faq1.html) Manfred
> > talks about the reasons why having defining words avaliable at run-time
> > is a bad idea. The reason he states in the end is one relating to
> > creation of variables that act the same way as they would in imperative
> > languages.
> >
> > I have one question and one (obvious) observation: 1) Wouldn't this
> > only be a problem with dynamically scoped languages? If Joy was
> > lexically scoped this wouldn't be an issue.
>
>
> Early Lisps were dynamically scoped, but since Landin's ISWIM both
> Scheme and Common Lisp are statically scoped, and so is Joy. All of
> them are dynamically typed: type checking occurs at run time. In Scheme
> and Common Lisp the static scoping is extensive: there are the global
> definitions of functions, the names of the formal parameters, LET
> expressions, lambda variables (and variables for assignment). With all
> these the scoping is an intricate affair due to the possible nesting. So
> the symbol table management becomes rather complex. In Joy there are
> just the global definitions, including those in HIDE's and MODULE's, and
> all the other things don't occur. So it is all very simple. For all
> these statically scoped languages a symbol means what it meant when the
> program started running, and in the case of complex nesting in Scheme or
> Common Lisp a symbol means what the enclosing scopes defined it to mean.
>
Oh, right. What confuses me is the execution of the following piece of code:
LIBRA
a == "a";
b == a;
a == "b".
b.
In most statically scoped languages it would return "a" - in Joy it returns "b".
Anyway I'm still curious and somewhat puzzled as to why you think having defining words
at run-time is a bad idea?
I don't see why it wouldn't be possible to have a language that includes a word such as
DEF2 that still does not allow creation imperative variables?
Expanding on your example using current-item:
[current-item 1] DEF2
current-item 3 + [] cons [current-item] swoncat DEF2
(* at this point current-item is 4 *)
[5] [[current-item [current-item 8] DEF2] times] infra
At this point the result could either be [4 4 4 4 4] or [4 8 8 8 8] depending on whether
[current-item [current-item 8] DEF2] quotation compiles and uses the definition of
current-item at the time the quotation was entered or whether it uses the most recent
definition of it.
The latter case resembles a variable in an imperative language but the former is purely
functional.
> This ignores macros in Scheme and Common Lisp. However, I do believe that
> some of the macro facilities available change matters somewhat. But I do
> not understand them well enough to really tell. Google "Oleg Scheme" for
> some wonderful stuff.
>
> > 2) The imperative notion of variables can be simulated with files as
> > well. Furthermore the whole concept of binding names to values and
> > functions is analogous to concepts of filesystems and databases.
>
> I think you are might be right here. But consider this:
>
> Assume the definition: DEFINE foo == 111 . (Note the space after the
> number - without it the scanner expects digits after the decimal point.)
> At runtime, put the string "DEFINE foo == 222 ." on the stack, write that
> string to a file, include that file, finally do "foo put.". All this in
> the same run. What do you get? 222 or 111 ? You get 111, because you are
> still in the same run. The new definition will only be read when the Joy
> interpreter is ready to read something, after it has executed the code for
> the current run. For the next run the included file will have been
> processed, of course, and foo will mean 222. And all this is how it
> should be, I think.
>
> Maybe John Cowan has something to say on this topic.
>
Yes but you could still save a value (let's say it's an integer) to a file, and later read it back
in and convert it back to an integer. You could do the same with strings, lists, pretty much
anything else. You don't need to include a file to create imperative variables.
As for the analogy, the main point of it was that I think it would be interesting if there was
a way to make files and words one and the same (by files I don't necessarily mean real files
in the filesystem but a structure that could be used in the same (or similar) way). It would
be even more interesting if there was a way to implement something like
that in a pure functional way that doesn't break concatenativity (not too much anyway).
I'm sure most of you have thought about something like this at one point or another or at
least thought about something similar or related to this.
Assuming you have access to defining words at run time you could do something like this
however doing it in a pure functional way is obviously problematic unless you recompile/
redefine every word that uses/reads a certain word/file every time that particular word/file
changes.
> - Manfred
Ivan
John Cowan — 2005-03-12 15:33:50
Ivan Tomac scripsit:
> Oh, right. What confuses me is the execution of the following piece
> of code:
>
> LIBRA
> a == "a";
> b == a;
> a == "b".
> b.
>
> In most statically scoped languages it would return "a" - in Joy it
> returns "b".
Actually, I couldn't find a single language in which this returns anything
but "b" (Perl, Scheme) or a compiler error (C, C++, Java). What language
did you have in mind?
Perl version:
sub a {return "a"}
sub b {a();}
sub a {return "b"}
print b();
Scheme version (for Common Lisp, change "define" to "defun"):
(define (a) "a")
(define (b) (a))
(define (a) "b")
(b)
C/C++ version:
# include <stdio.h>
char *a() {return "a";}
char *b() {return a();}
char *a() {return "b";}
main()) {puts(b();}
Java version:
class x {
private static String a() {return "a";}
private static String b() {return a();}
private static String a() {return "b";}
public static void main(String argv[]) { System.out.print(b()); }
}
> Yes but you could still save a value (let's say it's an integer) to a
> file, and later read it back in and convert it back to an integer. You
> could do the same with strings, lists, pretty much anything else. You
> don't need to include a file to create imperative variables.
Absolutely correct. However, you cannot change the meaning of any word
thereby.
--
LEAR: Dost thou call me fool, boy? John Cowan
FOOL: All thy other titles
http://www.ccil.org/~cowan
thou hast given away:
jcowan@...
That thou wast born with.
http://www.reutershealth.com
Ivan Tomac — 2005-03-12 16:52:09
--- In
concatenative@yahoogroups.com, John Cowan <cowan@c...> wrote:
> Ivan Tomac scripsit:
>
> > Oh, right. What confuses me is the execution of the following piece
> > of code:
> >
> > LIBRA
> > a == "a";
> > b == a;
> > a == "b".
> > b.
> >
> > In most statically scoped languages it would return "a" - in Joy it
> > returns "b".
>
> Actually, I couldn't find a single language in which this returns anything
> but "b" (Perl, Scheme) or a compiler error (C, C++, Java). What language
> did you have in mind?
>
> Perl version:
>
> sub a {return "a"}
> sub b {a();}
> sub a {return "b"}
> print b();
>
> Scheme version (for Common Lisp, change "define" to "defun"):
>
> (define (a) "a")
> (define (b) (a))
> (define (a) "b")
> (b)
>
> C/C++ version:
>
> # include <stdio.h>
> char *a() {return "a";}
> char *b() {return a();}
> char *a() {return "b";}
> main()) {puts(b();}
>
> Java version:
>
> class x {
> private static String a() {return "a";}
> private static String b() {return a();}
> private static String a() {return "b";}
> public static void main(String argv[]) { System.out.print(b()); }
> }
>
Hmm.. good point. I should have been more clear. I was thinking functional languages
along the lines of Caml and SML (and Haskell but then later I remembered that the
example wouldn't work in Haskell at all - not without changing the structure of the
example). I forgot about Scheme and I definitley wasn't even thinking of imperative
languages.
Either way I was wrong as clearly it's only a small subset of programming languages that
behave that way.
By the way your C version of the example wouldn't work (or rather compile) either as long
as it was compiled using a strict ANSI C compiler.
> > Yes but you could still save a value (let's say it's an integer) to a
> > file, and later read it back in and convert it back to an integer. You
> > could do the same with strings, lists, pretty much anything else. You
> > don't need to include a file to create imperative variables.
>
> Absolutely correct. However, you cannot change the meaning of any word
> thereby.
>
True. However I still can't see why having defining words at run time is not a good idea?
> --
> LEAR: Dost thou call me fool, boy? John Cowan
> FOOL: All thy other titles http://www.ccil.org/~cowan
> thou hast given away: jcowan@r...
> That thou wast born with. http://www.reutershealth.com
Ivan
John Cowan — 2005-03-12 17:06:24
Ivan Tomac scripsit:
> By the way your C version of the example wouldn't work (or rather
> compile) either as long as it was compiled using a strict ANSI
> C compiler.
Absolutely. The C and Java versions both generate compiler errors:
neither language allows procedures/methods to be redefined in the same
scope. C++ of course inherits C's rules in this respect.
> True. However I still can't see why having defining words at run time
> is not a good idea?
It's actually runtime *redefinition* that's problematic; runtime
definition of novel words wouldn't be a problem. If words can be
redefined at runtime, we have self-modifying code, which is not amenable
to static analysis.
--
John Cowan www.ccil.org/~cowan www.reutershealth.com
jcowan@...
We want more school houses and less jails; more books and less arsenals;
more learning and less vice; more constant work and less crime; more
leisure and less greed; more justice and less revenge; in fact, more of
the opportunities to cultivate our better natures. --Samuel Gompers
Ivan Tomac — 2005-03-12 17:43:46
--- In
concatenative@yahoogroups.com, John Cowan <cowan@c...> wrote:
> Ivan Tomac scripsit:
> It's actually runtime *redefinition* that's problematic; runtime
> definition of novel words wouldn't be a problem. If words can be
> redefined at runtime, we have self-modifying code, which is not amenable
> to static analysis.
>
I realize that, however there is no need to redefine existing words as I've tried to show
with an example. It is sufficient to bind names to new bindings - all the quotations that
have been defined with the previous definition keep using the previous definition.
Think about it as having the current state of the environment associated with each symbol
- if the environment changes the symbol keeps using the environment which existed at
the time when the quotation was created.
Obviously storing the whole state of the environment isn't necessary - just the actual
binding for that particular symbol.
> --
> John Cowan www.ccil.org/~cowan www.reutershealth.com jcowan@r...
> We want more school houses and less jails; more books and less arsenals;
> more learning and less vice; more constant work and less crime; more
> leisure and less greed; more justice and less revenge; in fact, more of
> the opportunities to cultivate our better natures. --Samuel Gompers
Ivan
Ehrenberg Daniel — 2005-03-12 20:37:22
> It's actually runtime *redefinition* that's problematic; runtime
> definition of novel words wouldn't be a problem. If words can be
> redefined at runtime, we have self-modifying code, which is not amenable
> to static analysis.
In Factor, words can be redefined at parsetime or runtime, yet Factor
has more static analysis implemented than Joy. How is this?
Redefinitions aren't reflected in compiled Factor code that uses the
redefined word. Example:
: x "a" ;
: y x ; compiled
: x "b" ;
y . ! "a"
x . ! "b"
You could add compiled declarations to x and it would do the same
thing. This isn't the best aspect of the Factor compiler, but it comes
up extremely rarely, and you can always declare it interpret-only.
Anyway, for data that changes, it's almost always better to use
Factor's dynamically scoped variables. These can hold quotations, if
you want, though then code won't be statically analyzable anyway if
you call a statically unknown quotation. The biggest time redefinition
really *needs* to be used is for something like holding a random
number seed. Joy has an ad-hoc mechanism for this, and either
redefining words or a full-fledged variable system would help, I
think.
Daniel Ehrenberg
John Cowan — 2005-03-13 06:27:56
Ivan Tomac scripsit:
> I realize that, however there is no need to redefine existing words
> as I've tried to show with an example. It is sufficient to bind names
> to new bindings - all the quotations that have been defined with the
> previous definition keep using the previous definition. Think about
> it as having the current state of the environment associated with
> each symbol - if the environment changes the symbol keeps using the
> environment which existed at the time when the quotation was created.
> Obviously storing the whole state of the environment isn't necessary -
> just the actual binding for that particular symbol.
I see no particular objection to this, but no particular benefit from
it either.
--
It was dreary and wearisome. Cold clammy winter still held way in this
forsaken country. The only green was the scum of livid weed on the dark
greasy surfaces of the sullen waters. Dead grasses and rotting reeds loomed
up in the mists like ragged shadows of long-forgotten summers.
--"The Passage of the Marshes"
http://www.ccil.org/~cowan
Ehrenberg Daniel — 2005-03-13 15:59:28
I failed to mention that there's a reason for all this. It's so when
developing/testing at the repl, you could load a file that contains
definitions for some of the words used in another file, without
reloading that other file. When doing stuff at the repl, things
normally aren't compiled, so this incongruity doesn't come up. In my
experience, Factor seems much better suited for interactive
development than Joy in general, and this is just one of many features
that helps it.
Daniel Ehrenberg
On Sat, 12 Mar 2005 15:37:22 -0500, Ehrenberg Daniel <microdan@...> wrote:
> > It's actually runtime *redefinition* that's problematic; runtime
> > definition of novel words wouldn't be a problem. If words can be
> > redefined at runtime, we have self-modifying code, which is not amenable
> > to static analysis.
>
> In Factor, words can be redefined at parsetime or runtime, yet Factor
> has more static analysis implemented than Joy. How is this?
> Redefinitions aren't reflected in compiled Factor code that uses the
> redefined word. Example:
> : x "a" ;
> : y x ; compiled
> : x "b" ;
> y . ! "a"
> x . ! "b"
> You could add compiled declarations to x and it would do the same
> thing. This isn't the best aspect of the Factor compiler, but it comes
> up extremely rarely, and you can always declare it interpret-only.
> Anyway, for data that changes, it's almost always better to use
> Factor's dynamically scoped variables. These can hold quotations, if
> you want, though then code won't be statically analyzable anyway if
> you call a statically unknown quotation. The biggest time redefinition
> really *needs* to be used is for something like holding a random
> number seed. Joy has an ad-hoc mechanism for this, and either
> redefining words or a full-fledged variable system would help, I
> think.
>
> Daniel Ehrenberg
>
Ivan Tomac — 2005-03-14 04:47:30
--- In
concatenative@yahoogroups.com, John Cowan <cowan@c...> wrote:
> I see no particular objection to this, but no particular benefit from
> it either.
>
Well the FAQ stated that the reason for having infix defining word was
because it was not a run-time operator so in an attempt to make that
fact more explicit it was made infix.
And the reason for it not being available at run-time was because it
would allow for mutable variables to be created, which may or may not
be the case depending on the scoping rules of the language.
So doing it this way would allow you to have defining words available
at run-time and there would be no need to have infix defining words.
> --
> It was dreary and wearisome. Cold clammy winter still held way in this
> forsaken country. The only green was the scum of livid weed on the dark
> greasy surfaces of the sullen waters. Dead grasses and rotting
reeds loomed
> up in the mists like ragged shadows of long-forgotten summers.
> --"The Passage of the Marshes"
http://www.ccil.org/~cowan
Ivan
phimvt@lurac.latrobe.edu.au — 2005-03-16 04:52:46
On Sat, 12 Mar 2005, Ivan Tomac wrote:
[..]
> Anyway I'm still curious and somewhat puzzled as to why you think
having
> defining words at run-time is a bad idea? I don't see why it wouldn't
> be possible to have a language that includes a word such as DEF2 that
> still does not allow creation imperative variables?
It would certainly be possible to have such a language that allows a DEF2,
and in some ways the early Lisps were just like that. But in some paper
the inventor of Lisp, John McCarthy, confessed that the early
implementations of Lisp had dynamic scope because he had misunderstood
Church's lambda calculus. I con't have a reference to that paper.
The accepted difficulty withh dynamic scope is that it is hard to reason
about programs.
[..]
> Yes but you could still save a value (let's say it's an integer) to
a file, and later read it back
> in and convert it back to an integer. You could do the same with strings, lists, pretty much
> anything else. You don't need to include a file to create imperative variables.
Yes, but the net effect is no different from just saving something on the
stack, and using it later, with a possibly long piece of code in between.
Suppose you wanted what in a procedural language would be an assignment "x
:= 123", and later use x somewhere. In a stack language this might look
like this: "123 >>x", meaning "push 123, move top-of-stack to variabe x".
Later use x somewhere, where x now means "push 123". And as you say
rightly, instead of doing ">>x", open a file called "x" for writing,
write the top-of-stack to the file, close the file. Do something else,
say, P, which does not involve the value stored in "x". Then open file
"x" for reading, read its content and push it onto the stack. Close the
file. This will do what you want. But instead of using a file you could do
the following:
123 [P] dip
After the dip has executed, the original 123 will still be there. If you
want to save more than one value, say three in all, you could write
123 [] cons cons cons [P] dip
and now all three will be available in a list from which you can take
the wanted items. To take an extreme case, where you want to restore
the entire stack (as a list), do this:
123 stack [P] dip
Hence, whatever can be done by using named files can be done by dip.
So, since Joy is purely functional without files, it remains purely
functional with files. (Thanks John Cowan.)
[..]
- Manfred
Ivan Tomac — 2005-03-17 13:21:57
--- In
concatenative@yahoogroups.com, phimvt@l... wrote:
> > Anyway I'm still curious and somewhat puzzled as to why you think
> having
> > defining words at run-time is a bad idea? I don't see why it wouldn't
> > be possible to have a language that includes a word such as DEF2 that
> > still does not allow creation imperative variables?
>
> It would certainly be possible to have such a language that allows a
DEF2,
> and in some ways the early Lisps were just like that. But in some paper
> the inventor of Lisp, John McCarthy, confessed that the early
> implementations of Lisp had dynamic scope because he had misunderstood
> Church's lambda calculus. I con't have a reference to that paper.
> The accepted difficulty withh dynamic scope is that it is hard to reason
> about programs.
>
Interesting.
However it's possible to have a word such as DEF2 and still have a
lexically scoped language without mutable variables as I've tried to
explain in the last few posts.
Although I haven't looked at the source code for Joy, I get the
feeling that it stores all definitions in a hashtable or something
similar. Any new definition seems to overwrite any previous definition
of the same name and every quotation that contains a reference to that
particular name starts using the new definition.
Alternatively you could use a stack for definitions. New definitions
are simply pushed on stack and any quotation that refers to old
bindings continues to use the old bindings.
Existing bindings do not change so there are no mutable variables and
so new bindings can get created at run-time without affecting any
existing quotations and definitions.
Defining words in such a language are no different to any other word
and there is no reason to separate them from the rest of the language.
> > Yes but you could still save a value (let's say it's an integer) to
> a file, and later read it back
> > in and convert it back to an integer. You could do the same with
strings, lists, pretty much
> > anything else. You don't need to include a file to create
imperative variables.
>
> Yes, but the net effect is no different from just saving something
on the
> stack, and using it later, with a possibly long piece of code in
between.
> Suppose you wanted what in a procedural language would be an
assignment "x
> := 123", and later use x somewhere. In a stack language this might look
> like this: "123 >>x", meaning "push 123, move top-of-stack to
variabe x".
> Later use x somewhere, where x now means "push 123". And as you say
> rightly, instead of doing ">>x", open a file called "x" for writing,
> write the top-of-stack to the file, close the file. Do something else,
> say, P, which does not involve the value stored in "x". Then open file
> "x" for reading, read its content and push it onto the stack. Close the
> file. This will do what you want. But instead of using a file you
could do
> the following:
>
> 123 [P] dip
>
> After the dip has executed, the original 123 will still be there. If you
> want to save more than one value, say three in all, you could write
>
> 123 [] cons cons cons [P] dip
>
> and now all three will be available in a list from which you can take
> the wanted items. To take an extreme case, where you want to restore
> the entire stack (as a list), do this:
>
> 123 stack [P] dip
>
> Hence, whatever can be done by using named files can be done by dip.
> So, since Joy is purely functional without files, it remains purely
> functional with files. (Thanks John Cowan.)
>
I don't doubt that Joy is purely functional - you, Billy and John
already convinced me Joy can be thought of as purely functional about
3-4 years ago when I joined this message board :)
I'm still thinking about your analogy between saving values on stack
and saving them to a file.
The problem with that is how would you simulate a self-contained
program that takes no parameters on the stack, reads a file, waits for
some user input and then writes something to a file?
The only way to do that without files would be to pass some sort of a
data structure that resembles a filesystem to every word that needs to
read or write files. Every such word would need to return the modified
filesystem structure as well.
This would be very inconveniant though so passing the filesystem
implicitly to every word makes sense. But at the same time it
introduces mutable variables.
What I'm curious about is why go to such an extent to eliminate
mutable variables (like separating defining words from the rest of the
language) when effectively files are mutable variables?
On another note here's a little state transformer in Joy (inspired by
monads, I decided to go back to playing with Haskell now that 6.4 is
out) - quite useless considering how you could easily do the same
thing by just using the stack but I thought it was still amusing:
LIBRA
checkSymbol == [] cons [intern =] concat [[list][false]] dip ifte ;
checkGet == [["get" checkSymbol] [pop dup]] dip ifte ;
checkSet == [["set" checkSymbol] [pop pop]] dip ifte ;
runS == [[[dip] checkSet] checkGet] step .
5 2 [[7 +] get [+ 55] set [5] get [+]] runS .
(* final result on stack: 14 60 55 *)
> - Manfred
Ivan
John Cowan — 2005-03-17 13:43:13
Ivan Tomac scripsit:
> Although I haven't looked at the source code for Joy, I get the
> feeling that it stores all definitions in a hashtable or something
> similar. Any new definition seems to overwrite any previous definition
> of the same name and every quotation that contains a reference to that
> particular name starts using the new definition.
Correct. This is the usual Lisp/Scheme/APL style, what I called
"whacking on a workspace".
> Alternatively you could use a stack for definitions. New definitions
> are simply pushed on stack and any quotation that refers to old
> bindings continues to use the old bindings.
Yes, we could. But that implements lexical scoping if and only if
there are no defining words at run time (as is the case in MLish
languages). Indeed, the strict interpretation of such a feature
renders it useless. Suppose we write the definition of a word A
which at runtime defines the word B. But there is no way for A
or any pre-existing word to invoke B, since it was not already
defined when A was compiled. So now we need a new word meaning
"invoke the most recent (dynamic) definition of a specified word",
and that breaks lexical scoping completely.
> The only way to do that without files would be to pass some sort of a
> data structure that resembles a filesystem to every word that needs to
> read or write files. Every such word would need to return the modified
> filesystem structure as well.
Quite right, which is why the Joy words that do I/O leave the file
objects on the stack (the Joy version of a monad, and much simpler
than the lazy-functional version!).
> What I'm curious about is why go to such an extent to eliminate
> mutable variables (like separating defining words from the rest of the
> language) when effectively files are mutable variables?
When Manfred wrote Joy0, he was concerned mainly with proof of concept.
When I extended it to make Joy1 (the current reference implementation),
I wanted Joy to have all the capabilities of ANSI C, so files and floats
arrived in the language despite their well-known theoretical difficulties.
--
Is a chair finely made tragic or comic? Is the John Cowan
portrait of Mona Lisa good if I desire to see
jcowan@...
it? Is the bust of Sir Philip Crampton lyrical, www.ccil.org/~cowan
epical or dramatic? If a man hacking in fury www.reutershealth.com
at a block of wood make there an image of a cow,
is that image a work of art? If not, why not? --Stephen Dedalus
Ivan Tomac — 2005-03-17 15:51:10
--- In
concatenative@yahoogroups.com, John Cowan <cowan@c...> wrote:
> > Alternatively you could use a stack for definitions. New
definitions
> > are simply pushed on stack and any quotation that refers to old
> > bindings continues to use the old bindings.
>
> Yes, we could. But that implements lexical scoping if and only if
> there are no defining words at run time (as is the case in MLish
> languages). Indeed, the strict interpretation of such a feature
> renders it useless. Suppose we write the definition of a word A
> which at runtime defines the word B. But there is no way for A
> or any pre-existing word to invoke B, since it was not already
> defined when A was compiled. So now we need a new word meaning
> "invoke the most recent (dynamic) definition of a specified word",
> and that breaks lexical scoping completely.
>
While it doesn't add any expressive power to the language it
basically makes defining words no different from any other word which
means there is no need to make them stand out - makes the syntax more
consistent so I wouldn't say it's useless.
There is no need to add a new word to invoke the most recent
definition of the specified word - that would clearly add dynamic
scoping to the language.
I see nothing wrong with B being defined at run-time by A even if A
cannot use it. Anyway I think such a thing would be quite rare - to
have a word defined within another rather then at the top level - but
the whole point of it is that it wouldn't break lexical scoping rules
of the language even if it was used within a quotation like that.
> > The only way to do that without files would be to pass some sort
of a
> > data structure that resembles a filesystem to every word that
needs to
> > read or write files. Every such word would need to return the
modified
> > filesystem structure as well.
>
> Quite right, which is why the Joy words that do I/O leave the file
> objects on the stack (the Joy version of a monad, and much simpler
> than the lazy-functional version!).
>
I'm not sure that can be compared to a monad, or at least not for that
reason. You could say the same thing about imperative languages: all C
functions that operate on files take a file handle or a stream as one
of the arguments.
The problem with that is what happens once the file is closed? The
file object or the handle disappears while the monad persists and gets
passed on as a continuation.
I think a better analogy would be that the whole filesystem gets
implicitly passed as an argument to every word. Or rather that the
whole state of the world or the environment gets passed as an argument
to every word.
> > What I'm curious about is why go to such an extent to eliminate
> > mutable variables (like separating defining words from the rest
of the
> > language) when effectively files are mutable variables?
>
> When Manfred wrote Joy0, he was concerned mainly with proof of
concept.
> When I extended it to make Joy1 (the current reference
implementation),
> I wanted Joy to have all the capabilities of ANSI C, so files and
floats
> arrived in the language despite their well-known theoretical
difficulties.
>
Fair enough. That makes sense.
> --
> Is a chair finely made tragic or comic? Is the John Cowan
> portrait of Mona Lisa good if I desire to see jcowan@r...
> it? Is the bust of Sir Philip Crampton lyrical,
www.ccil.org/~cowan
> epical or dramatic? If a man hacking in fury
www.reutershealth.com
> at a block of wood make there an image of a cow,
> is that image a work of art? If not, why not?
--Stephen Dedalus
Ivan
phimvt@lurac.latrobe.edu.au — 2005-03-18 08:49:04
I have added a new item to the Joy page, in section 2 towards the end,
the third-last item. Alternatively, view it directly:
http://www.latrobe.edu.au/philosophy/phimvt/joy/jp-reprod.html
It isn't quite finished, and there still are lots of typos due to
key-bounce. I don't quite know when I can work on it again.
In the meantime, enJoy.
- Manfred
Narcoleptic Electron — 2005-03-18 15:56:26
Ivan Tomac wrote:
> Or rather that the
> whole state of the world or the environment gets passed as an argument
> to every word.
This is what the Clean language does.
http://www.cs.ru.nl/~clean/