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

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

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)))) 

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

> 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

It's all down to having or not having a compiler.


UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe

Reply via email to