Thread: Re: [q-lang-users] Polynomial module.
Brought to you by:
agraef
From: Albert G. <Dr....@t-...> - 2006-10-31 18:13:33
|
Hi Rob, I'm redirecting this to the list so that we can discuss it here. I tend to agree that this problem calls for a general solution which also adresses the weirdness of lambda reported in Eddie's recent post. Rob Hubbard wrote: > If you run polynomial.q with --pedantic, you may notice the message > Warning polynomial.q, line 722: undeclared variable symbol `Y' > which comes from my use of your sieve: > sieve {X|Xs} = {X|sieve {Y:Y in Xs,Y mod X<>0}}; > I think I've seen similar warnings for lambdas. > Is that a bug? From a recent posting on the mailing list, I understand > that such variables are not bound as they would be with a 'real' lambda, > but could the warnings on such 'pseudo-bound' variables be suppressed? It's not a bug, but a misfeature, or a wart if you prefer. Currently there is no way for the interpreter to distinguish the "pseudo bindings" performed by lambda and list/stream comprehensions from ordinary uses of free variables. Therefore right now the only way to get rid of those --pedantic warnings is to explicitly declare the symbols as free variables (because that's just what they are, as far as the interpreter is concerned). You can also do that with embedded "var" keywords in the definitions. But the warnings are only a symptom, not the real cause. Having meditated about this some more, I think that it might be useful if the interpreter was able to deal with variable bindings performed by special forms like lambda and listof/streamof. But this needs some new kind of "variable scoping" declarations for special forms, and I haven't found a general solution for that yet. Of course I could hardwire the desired custom scoping rules for lambda and comprehensions into the interpreter, but that's not a real solution, because the programmer may wish to derive his own special forms from these, or create his own variable-binding special forms from scratch. So what we need are some special directives which tell the interpreter which parameters of a special form bind variables and which other parameters the scope of these variables extends to. Something like this: public special lambda __bind__ X __scope__ Y; Unfortunately, such a simple construct won't do the trick for listof/streamof, since these actually perform their bindings in the "in" clauses, so the lexical scoping rules would be rather complicated in this case. And such a feature might also wreak havoc on the ability to treat lambdas as ordinary expressions which can be constructed and manipulated at runtime. Any ideas, anyone? I don't recall seeing anything like this in any other programming language, but Q is also rather unusual in that it allows the programmer to define his own special forms (apart from the macro facilities of Lisp, but these are compile-time only). Cheers, Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Keith T. <kaz...@ea...> - 2006-11-03 03:04:03
|
If I may offer my two cents ... --- Albert Graef <Dr....@t-...> wrote: --- var Y in --- sieve {X|Xs} = {X|sieve {Y:Y in Xs,Y mod X<>0}}; [1] one advantage wrt. writing "var Y in" : definitions remain free of clutter; [2] one disadvantage wrt. writing "var Y in" : it takes two (2) lines of code to do the work of one. Paul Graham once declared that "succinctness is power" [ http://www.paulgraham.com/power.html ]; and personally, I prefer writing one slightly longer line of code over writing two lines of code. --- Albert Graef <Dr....@t-...> wrote: - sieve {X|Xs} = {X|var Y : sieve {Y:Y in Xs,Y mod X<>0}}; [1] one advantage wrt. in-ining "var Y : " : only one (1) line of code is required (see above); [2] one (possible) disadvantage wrt. in-ining "var Y : " : are we overloading the colon <:> in an ambiguous way? Obviously, I do not know; what about it, Albert? Other than this question, it looks nice and fairly "Q-ish". Alternatives : [a] sieve {X|Xs} = {X|local Y : sieve {Y:Y in Xs,Y mod X<>0}}; [b] sieve {X|Xs} = {X|var Y in sieve {Y:Y in Xs,Y mod X<>0}}; [c] sieve {X|Xs} = {X|local Y in sieve {Y:Y in Xs,Y mod X<>0}}; [d] sieve {X|Xs} = {X|Y| sieve {Y:Y in Xs,Y mod X<>0}}; Wait a minute... I think [d] is a "ringer". It looks like Smalltalk to me! =) Cheers, Keith |
From: Albert G. <Dr....@t-...> - 2006-11-03 07:43:31
|
Keith Trenton wrote: > - sieve {X|Xs} = {X|var Y : sieve {Y:Y in Xs,Y mod X<>0}}; > > [1] one advantage wrt. in-ining "var Y : " : only one (1) line of code is required (see above); The other advantage is that the scope of the variable(s) would be restricted just to a single expression instead of the entire rule. > [2] one (possible) disadvantage wrt. in-ining "var Y : " : are we overloading the colon <:> in an ambiguous way? I don't think so. The "var" should disambiguate it. > [a] sieve {X|Xs} = {X|local Y : sieve {Y:Y in Xs,Y mod X<>0}}; We already have the "var" keyword so why not use it? > [b] sieve {X|Xs} = {X|var Y in sieve {Y:Y in Xs,Y mod X<>0}}; "in" doesn't work, it can't be a predefined keyword, because it's declared as a user-defined operator in the standard library. That's why I picked the colon instead. > [d] sieve {X|Xs} = {X|Y| sieve {Y:Y in Xs,Y mod X<>0}}; This looks nice but introduces syntactic ambiguities because | is also used in the list/stream syntax. E.g., consider {X|bla X}. Is that a stream with head X and tail bla X or a single-element stream with a var declaration in it? Cheers, Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Rob H. <hub...@gm...> - 2006-11-02 22:54:04
|
Hello Albert, Thanks for the information... On 31/10/06, Albert Graef <Dr....@t-...> wrote: > Hi Rob, > > I'm redirecting this to the list so that we can discuss it here. I tend > to agree that this problem calls for a general solution which also > adresses the weirdness of lambda reported in Eddie's recent post. > > Rob Hubbard wrote: > > If you run polynomial.q with --pedantic, you may notice the message > > Warning polynomial.q, line 722: undeclared variable symbol `Y' > > which comes from my use of your sieve: > > sieve {X|Xs} = {X|sieve {Y:Y in Xs,Y mod X<>0}}; > > I think I've seen similar warnings for lambdas. > > Is that a bug? From a recent posting on the mailing list, I understand > > that such variables are not bound as they would be with a 'real' lambda, > > but could the warnings on such 'pseudo-bound' variables be suppressed? > > It's not a bug, but a misfeature, or a wart if you prefer. Currently > there is no way for the interpreter to distinguish the "pseudo bindings" > performed by lambda and list/stream comprehensions from ordinary uses of > free variables. Therefore right now the only way to get rid of those > --pedantic warnings is to explicitly declare the symbols as free > variables (because that's just what they are, as far as the interpreter > is concerned). You can also do that with embedded "var" keywords in the > definitions. I understand. I would like to use inline "var"s. Unfortunately, that might then hide another undeclared symbol elsewhere in my script. One option is to "postfix" any free variable with the name of the function definition containing it. For example: sieve {X|Xs} = {X|sieve {Y_sieve: Y_sieve in Xs, Y_sieve mod X<>0}}; The "workaround" I've opted for is to have an explicit var FreeVar; early in my *.q file, and to use that in all contexts where the variable is intentionally free. (Similarly, if more that one was needed anywhere, I could use var FreeVar1; var FreeVar2; //and so on... ) > But the warnings are only a symptom, not the real cause. Having > meditated about this some more, I think that it might be useful if the > interpreter was able to deal with variable bindings performed by special > forms like lambda and listof/streamof. But this needs some new kind of > "variable scoping" declarations for special forms, and I haven't found a > general solution for that yet. Of course I could hardwire the desired > custom scoping rules for lambda and comprehensions into the interpreter, > but that's not a real solution, because the programmer may wish to > derive his own special forms from these, or create his own > variable-binding special forms from scratch. > > So what we need are some special directives which tell the interpreter > which parameters of a special form bind variables and which other > parameters the scope of these variables extends to. Something like this: > > public special lambda __bind__ X __scope__ Y; > > Unfortunately, such a simple construct won't do the trick for > listof/streamof, since these actually perform their bindings in the "in" > clauses, so the lexical scoping rules would be rather complicated in > this case. And such a feature might also wreak havoc on the ability to > treat lambdas as ordinary expressions which can be constructed and > manipulated at runtime. > > Any ideas, anyone? I don't recall seeing anything like this in any other > programming language, but Q is also rather unusual in that it allows the > programmer to define his own special forms (apart from the macro > facilities of Lisp, but these are compile-time only). I'm not sufficiently competent in Q to offer any good suggestions yet I'm afraid. However, I can see that what is needed is a way to bound the scope of a free variable or "var" declaration. Perhaps something along the lines of var Y in sieve {X|Xs} = {X|sieve {Y:Y in Xs,Y mod X<>0}}; would be a possible approach. > Cheers, > Albert > > -- > Dr. Albert Gr"af > Dept. of Music-Informatics, University of Mainz, Germany > Email: Dr....@t-..., ag...@mu... > WWW: http://www.musikinformatik.uni-mainz.de/ag > Thanks, Rob. |
From: Rob H. <hub...@gm...> - 2006-11-02 22:55:54
|
That should have been sieve {X|Xs} = {X|sieve {var Y_sieve: Y_sieve in Xs, Y_sieve mod X<>0}}; below. I forgot the "var". Sorry. Rob. On 02/11/06, Rob Hubbard <hub...@gm...> wrote: > Hello Albert, > > Thanks for the information... > > On 31/10/06, Albert Graef <Dr....@t-...> wrote: > > Hi Rob, > > > > I'm redirecting this to the list so that we can discuss it here. I tend > > to agree that this problem calls for a general solution which also > > adresses the weirdness of lambda reported in Eddie's recent post. > > > > Rob Hubbard wrote: > > > If you run polynomial.q with --pedantic, you may notice the message > > > Warning polynomial.q, line 722: undeclared variable symbol `Y' > > > which comes from my use of your sieve: > > > sieve {X|Xs} = {X|sieve {Y:Y in Xs,Y mod X<>0}}; > > > I think I've seen similar warnings for lambdas. > > > Is that a bug? From a recent posting on the mailing list, I understand > > > that such variables are not bound as they would be with a 'real' lambda, > > > but could the warnings on such 'pseudo-bound' variables be suppressed? > > > > It's not a bug, but a misfeature, or a wart if you prefer. Currently > > there is no way for the interpreter to distinguish the "pseudo bindings" > > performed by lambda and list/stream comprehensions from ordinary uses of > > free variables. Therefore right now the only way to get rid of those > > --pedantic warnings is to explicitly declare the symbols as free > > variables (because that's just what they are, as far as the interpreter > > is concerned). You can also do that with embedded "var" keywords in the > > definitions. > > I understand. > > I would like to use inline "var"s. Unfortunately, that might then hide > another undeclared symbol elsewhere in my script. > > One option is to "postfix" any free variable with the name of the > function definition containing it. > For example: > sieve {X|Xs} = {X|sieve {Y_sieve: Y_sieve in Xs, Y_sieve mod X<>0}}; > > The "workaround" I've opted for is to have an explicit > var FreeVar; > early in my *.q file, and to use that in all contexts where the > variable is intentionally free. > > (Similarly, if more that one was needed anywhere, I could use > var FreeVar1; > var FreeVar2; > //and so on... > ) > > > But the warnings are only a symptom, not the real cause. Having > > meditated about this some more, I think that it might be useful if the > > interpreter was able to deal with variable bindings performed by special > > forms like lambda and listof/streamof. But this needs some new kind of > > "variable scoping" declarations for special forms, and I haven't found a > > general solution for that yet. Of course I could hardwire the desired > > custom scoping rules for lambda and comprehensions into the interpreter, > > but that's not a real solution, because the programmer may wish to > > derive his own special forms from these, or create his own > > variable-binding special forms from scratch. > > > > So what we need are some special directives which tell the interpreter > > which parameters of a special form bind variables and which other > > parameters the scope of these variables extends to. Something like this: > > > > public special lambda __bind__ X __scope__ Y; > > > > Unfortunately, such a simple construct won't do the trick for > > listof/streamof, since these actually perform their bindings in the "in" > > clauses, so the lexical scoping rules would be rather complicated in > > this case. And such a feature might also wreak havoc on the ability to > > treat lambdas as ordinary expressions which can be constructed and > > manipulated at runtime. > > > > Any ideas, anyone? I don't recall seeing anything like this in any other > > programming language, but Q is also rather unusual in that it allows the > > programmer to define his own special forms (apart from the macro > > facilities of Lisp, but these are compile-time only). > > I'm not sufficiently competent in Q to offer any good suggestions yet > I'm afraid. However, I can see that what is needed is a way to bound > the scope of a free variable or "var" declaration. > > Perhaps something along the lines of > > var Y in > sieve {X|Xs} = {X|sieve {Y:Y in Xs,Y mod X<>0}}; > > would be a possible approach. > > > Cheers, > > Albert > > > > -- > > Dr. Albert Gr"af > > Dept. of Music-Informatics, University of Mainz, Germany > > Email: Dr....@t-..., ag...@mu... > > WWW: http://www.musikinformatik.uni-mainz.de/ag > > > > Thanks, > Rob. > |
From: Albert G. <Dr....@t-...> - 2006-11-02 23:27:55
|
Rob Hubbard wrote: > I would like to use inline "var"s. Unfortunately, that might then hide > another undeclared symbol elsewhere in my script. Right. :( Those inline var's should really be confined to the lexical scope of a single definition. Why haven't I thought about this before?? > var Y in > sieve {X|Xs} = {X|sieve {Y:Y in Xs,Y mod X<>0}}; Not a bad idea. Another possible approach would be to attach an inline var to an expression, as in: sieve {X|Xs} = {X|var Y : sieve {Y:Y in Xs,Y mod X<>0}}; The scope of the var declaration would then be limited to the expression after the ':'. Eddie's example could then be written as: outliers X = filter (var X : \X . (X < LF) or (X > RF)) X ...; That would be much more useful than the inline var declarations we have now. Opinions? Anyone against this change? Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |