Hi Alex, > No, sorry, this is not a solution to the task. It doesn't use a first > class environment.
yes, that's what I said in the previous email. However, the part starting with SYMBOL-MACROLET is _the_ interesting part, which you skipped. I probably didn't explaing myself well, sorry. > Let me explain for the public (as you already know the details): The > 'envs' list above is a just a normal data structure, holding a list of > *values*. Yes, that's in the 1st try example to understand what is the task about. The second and third example are representing the environment exactly like in PicoLisp. > A first class environment encapsulates *bindings* of symbols and > values. The important point is that you can handle whole bindings as > first class items, creating and passing them around independent of the > code that might use them in some other place. Yes, that's what the second and third example does. SYMBOL-MACROLET allows me to do it. Think of it this way: in PicoLisp, how the environment is hardcoded to be alist and binding lookup mechanism assumes this. However, in Common Lisp, I used SYMBOL-MACROLET to substitute symbol occurrences with some code, which can do the symbol lookup for example, from an "environment" that can look like an alist, like in PicoLisp, but it could be any other datastructure (the first example used positional list for demonstration). It could be a hastable or it could even be something existing on a remote computer but it would still look like a variable to the programmer. And this also allows me to create first class environments with the same features like in PicoLisp. Notice, the second example is written exactly like in PicoLisp (minus the argument declaration): (job e (n cnt) (format t "~4d" n) (unless (= 1 n) (incf cnt) (setq n (if (= 1 (logand 1 n)) (1+ (* n 3)) (/ n 2))))) SYMBOL-MACROLET allowed me to implement 'job' with the same semantics like in PicoLisp. The only difference is that that I declare, at the point of usage, the bindings which I am going to use. However, that doesn't change much on the ability to create, save, load, send over the wire the environment, same as in picolisp. I declared the bindings there to inform the compiler which would otherwise try to automatically find the bindings in the default lexical environment. Also note, that my job macro has the same apriori information about the environment as the 'job' fexpr in Picolisp, i.e. it is an alist with symbol value pairs that are "interpreted" as variable bindings. Also note, that in Common Lisp, I could also implement the job macro without that declaration, because I could walk the tree representation of the code of job's 'prg' and find the free variables. However, although it would be automatic, it would be like defining a function and not saying what arguments it accepts. This way, I state my intentions and the compiler checks them. In short, SYMBOL-MACROLET allows me to do the same trick as 'job' uses with the same semantics. It has nothing to do with dynamic scope. 'job' allows one to manually create closures as closures in PicoLisp cannot be automatically inferred because there is no compiler to infer them. Here a brief sketch of job without declaring the arguments: (defmacro job (env &body body) (let ((x (gensym)) (args (find-free-variables body))) `(let ((,x ,env)) (symbol-macrolet (,@(mapcar (lambda (y) `(,y (cdr (assoc ',y ,x)))) args)) ,@body)))) where FIND-FREE-VARIABLES would walk the body tree structure and return a list of the variables that are free. > And the code must for itself declare the variables (lambda, macrolet > etc.), violating the separation of binding the symbols in the > environment, and the actual code. Does your function: (de disable (Flg) (and Flg (=: able)) ) violate the separation of binding the symbols in the environment and the actual code? Then wouldn't it be better to always write: (de disable (and Flg (=: able)) ) > For example, the PicoLisp GUI uses first class environments to pass > bindings from one frame or dialog to another, across HTTP > transactions. > > Consider this code fragment > > (gui '(+Button) "Do something" > '(dialog (env '(Foo Bar Baz (Cnt . 3)) 'X (calcX)) > (<grid> 2 > ... directly using Foo, Bar, Baz, Cnt, and X ... ) > (okButton) ) ) Yes, that's what closures do, they hold on to the state across invocations. It's also what classes do btw. There's no magic about it. The difference between PicoLisp and Common Lisp is that in PicoLisp, one have to create the closures manually, while in lisps with a compiler it is a job for the compiler. The example I wrote demonstrates, that I can still create the environments manually if I wish to do so in Common Lisp. > When the button "Do something" is pressed, the environment (i.e. the > variables Foo, Bar and Baz and their current values, plus Cnt and X) > is passed through the round-trip of the HTTP POST transaction to the > HTML form building the dialog. The code in the dialog (here in the > '<grid>' body) can simply "use" these variables. Yes, again there's nothing that lexical binding prevents here. > There is only a single place where these variables are "declared", the > rest is abstracted away because the whole environment is passed into > the dialog. Not declaring the variables is a cosmetic issue, nothing to do with dynamic binding. One could say that in PicoLisp one is in fact simulating lexical environments manually with 'job'. > Though in this example the creation and usage of that environment are > still in the same lexical scope, this doesn't have to be the case. The > environment might as well be read from a file, or passed across a > network connection in an RPC call. Same holds for my code. It has nothing to do with dynamic scope;-) You still need to create the environent somewhere, you need to pass it somehow to the point where it's used, and then it is used. > No, it has indeed. To my understanding, you can't (by definition) > separate variables and code in lexical scopes (see below). You can and that's what SYMBOL-MACROLET allows me to do! Basically, the programmer writes code and thinks he is using variables, but the SYMBOL-MACROLET turns those variables/symbols into some code that semantically looks like working with a variable but can be arbitrary code (something accessing the first class environment in my example). It's like telling the compiler that this symbol doesn't represent a lexical variable but rather a proxy accessor to something else. > But I think it can't be done right with lexical scope. I disagree. I just showed you how:-) > But still it needs an explicit "declaration", with the 'args' argument > to 'job' (n cnt), making it a normal function call to set up the > environment. The code needs an a explicit (a priori) knowledge of the > variables, to satisfy the lexical requirements. As I already mentioned above, the job macro _could_ infer the arguments itself. The prg argument is a sexp after all! > With that, a Picolisp call like > > (job <environment> > <body> ) > > becomes to > > (funcall > (job (var1 var2 var3 ...) > <body> ) > <environment> ) > > which does not really taste like simply executing some code body > within an environment. This might explain why first class environments > are not an issue in CL. You missed the most important part, the SYMBOL-MACROLET part. That changes the meaning of the var1... symbols from "symbol representing a variable" to "symbol representing access to something". > Can you submit it to RosettaCode? I don't have an account there, so please feel free to submit the code there. It's all down to having or not having a compiler. Cheers, Tomas -- UNSUBSCRIBE: mailto:email@example.com?subject=Unsubscribe