After reading a lot of documentation regarding Lisp eval-when operator I still can't understand its uses, I know with this operator I can control the evaluation time of my expressions but I can't figure out any example where this may be applicable ?
Best Regards,
utxeee.
Compilation of a Lisp file
Take for example the compilation of a Lisp file. The Lisp compiler processes the top-level forms. These can be arbitrary Lisp forms, DEFUNs, DEFMACROS, DEFCLASS, function calls,...
The whole story how the file compiler works is too complex to explain here, but a few things:
the file compiler generates code for a (DEFUN foo () ) form. But it does not execute the defun form. Thus during compilation it is known that there is a function FOO, but the code of ˋFOOˋ is not available during the compilation. The compiler generates the code for the compiled file, but does not keep it in memory. You can't call such a function at compile time.
for macros this works slightly different: (DEFMACRO BAZ ...). The file compiler will not only compile the macro and note that it is there, but it will also make the macro available at compilation time. It is loaded into the compiler environment.
Thus imagine the sequence of forms in a file:
(defmacro baz ...)
(defun foo () (baz ...))
This works because the file compiler knows the macro BAZ and when it compiles the code for FOO, then it can expand the macro form.
Now let's look at the following example:
(defun bar (form) ...)
(defmacro baz (form) (bar form))
(defun foo () (baz ...))
Above will not work. Now the macro BAZ uses the function BAR by calling it. When the compiler tries to compile the function FOO, it can't expand the BAZ macro, because BAR can't be called, because the code of BAR is not loaded into the compile-time environment.
There are two solutions to this:
compile and load BAR earlier using a separate file.
Use EVAL-WHEN
Example for EVAL-WHEN:
(eval-when (:compile-toplevel :execute :load-toplevel)
(defun bar (form) ...)
)
(defmacro baz (form) (bar form))
(defun foo () (baz ...))
Now the EVAL-WHEN instructs the file compiler to actually run the DEFUN form during compilation. The effect of this is: the file compiler now knows the definition of BAR at compile time. Thus it is available later, when the file compiler need to call BAR during macro expansion of the usage of BAZ.
One could use only :compile-toplevel, when the function would not be needed after the compilation of the file. If it is used later, then we need to make sure that it gets loaded.
So EVAL-WHEN allows to specify if a particular piece of code should be run
during compilation of a file
during loading of a file
during execution
EVAL-WHEN is not used that often in user code. If you use it, then you should ask yourself if you really need it.
Related
How to undefine a variable in Scheme? Is this possible?
You're touching a nerve here. Scheme doesn't have a very clear standard notion of how top-level environments work. Why? Because the Scheme standards represent a compromise between two sets of people with very different ideas of how Scheme should work:
The interpretive crowd, who sees the top-level environment as you describe above: a runtime hash-table where bindings are progressively added as program interpretation proceeds.
Then there's the compilation crowd, who sees the top-level environment as something that must be fully computable at compilation time (i.e., a compiler must be able to conclusively identify all of the names that will be bound in the top-level environment).
Your "how do I undefine a variable" question only makes sense in the first model.
Note that the interpretive model, where a program's top-level bindings depend on what code paths get taken, makes efficient compilation of Scheme code much harder for many reasons. For example, how can a Scheme compiler inline a procedure invocation if the name of the procedure is a top-level binding that may not just change during runtime, but even disappear into nothingness?
I'm firmly in the compilation camp here, so what I would recommend to you is to avoid writing code that relies on the ability to add or remove top-level bindings at runtime, or even that requires the use of top-level variables (though those are often unavoidable). Some Scheme systems (e.g., Racket) are able to produce reasonably good compiled code, but if you make those assumptions you'll trip them up in that regard.
In Scheme, variables are defined with either lambda, or one of the various lets. If you want one of them to be 'undefined' then all you need to do is leave the scope that they're in. Of course, that's not really undefining them, it's just that the variable is no longer bound to its previous definition.
If you're making top level definitions, using (define), then technically you're defining a function. Since Scheme is functional, functions never really go away. I suppose that technically, it's stored in some sort of environment function somewhere, so if you were intimately familiar with your implementation (and it's not safeguarded somehow) you could probably overwrite it with your own definition of the globabl environment. Barring that, I'd say that your best bet would be to redefine the function to return the null list- that's really as empty as you get.
Scheme (R7RS) has no standard compliant way to remove a top-level binding.
If you evaluate a non existing variable, you get an error:
(eval 'a)
; => ERROR: undefined variable: a
If you define it, the variable gets added to the top-level environment.
(define a 1)
(eval 'a)
; => 1
As from now no matter what you do, you will not get an error, if you access the variable.
If you set it to false, you will get false:
(set! a #f)
(eval 'a)
; => #f
Even if you set it to something unspecified, it is unlikely that you get an error:
(set! a (if #f #t))
(eval 'a)
; =>
But Schemes may have a non-standard way to remove a top-level binding. MIT Scheme provides the function unbind-variable.
As stated in the other answers there is no standard way of manipulating the namespace in Scheme. For a specific implementation there might be a solution.
In Racket the top-level variables are stored in a namespace. You can remove a variable using namespace-undefined-variable.
There is no way of removing a local variable.
http://docs.racket-lang.org/reference/Namespaces.html?q=namespace#%28def.%28%28quote.~23~25kernel%29._namespace-undefine-variable%21%29%29
(set! no-longer-needed #f)
Does this achieve the effect you want? You can also use define at the top level.
guile> (define nigel "lead guitar")
guile> nigel
"lead guitar"
guile> (define nigel #f)
guile> nigel
#f
guile>
You could then re-define the variable. This all depends on the scope of the variables, of course: see Greg's answer.
You cannot unbind a variable in standard Scheme. You could set! the variable to 'undefined, I guess, or you could write a metainterpreter which reifies environments, allowing you to introduce your own notion of undefining variables.
I think, if your point is to do the equivalent of "free" or de-allocate, then no you're pretty much out of luck. you can't de-allocate a variable. you CAN re-define it to something small, like #f, but once you've done (define foo 'bar) the variable foo will exist in some form until you end the program.
On the other hand, if you use let, or letrec, of course, the name only exists until the relevant close paren...
I think your question is not stupid. In AutoLISP has unexisting (undefined) variable apriori supposted value "nil" (even if the variable does not exist in memory - it means - if it is not in a table of variables - then the value is "nil" - "false"). It means also false. And it is also empty list. If you program some kind of list processing function, it is enough to make initial test only by:
(if input-list ....)
When you want to explicitly undefine any variable, you may do this:
(setq old-var nil); or: (setq old-var ())
I like it. The keyword "setq" means "define". What is better on bounding and unbounding variables in other dialects? You must test if they exist, if they are lists, you need garbage-collector, you may not undefine variable to explicitly free memory. Following command can not be written if variable "my-list" is not defined:
(define my-list (cons 2 my-list))
So I think the AutoLISP way is for programming much better. Possibilities, that I written, you may use there. Unfortunately the AutoLISP works in some CAD engineering graphical systems only.
In Scheme R7RS there is both a load and include form.
Include is described as:
Semantics: Both include and include-ci take one or
more filenames expressed as string literals, apply an
implementation-specific algorithm to find corresponding files, read
the contents of the files in the specified order as if by repeated
applications of read, and effectively re- place the include or
include-ci expression with a begin expression containing what was read
from the files. The difference between the two is that include-ci
reads each file as if it began with the #!fold-case directive, while
include does not. Note: Implementations are encouraged to search for
files in the directory which contains the including file, and to
provide a way for users to specify other directories to search.
Load is described as:
An implementation-dependent operation is used to trans- form filename
into the name of an existing file con- taining Scheme source code. The
load procedure reads expressions and definitions from the file and
evalu- ates them sequentially in the environment specified by
environment-specifier. If environment-specifier is omitted,
(interaction-environment) is assumed. It is unspecified whether the
results of the expres- sions are printed. The load procedure does not
af- fect the values returned by current-input-port and
current-output-port. It returns an unspecified value. Rationale: For
portability, load must operate on source files. Its operation on other
kinds of files necessarily varies among implementations.
What is the rationale for the two forms? I assume it is historic. Is there any import semantic difference between the two forms? I see that load can optionally include an environment specifier and include doesn't have that. And include-ci has no direct equivalent using load. But comparing load and include alone, what is the difference and is it important?
I think the critical difference is that include is syntax (or in traditional Lisp terms, it is a macro) while load is a function. In traditional Lisp terms (there will be a much more formal definition of this in Scheme terms which I am not competent to give) this means that include does its work at macro-expansion time, while load does its work at evaluation time. These times can be very different for an implementation which has a file compiler: macro-expansion time happens during compilation of files, while evaluation happens only much later, when the compiled files are loaded.
So, if we consider two files, f1.scm containing
(define foo 1)
(include "f2.scm")
and f2.scm containing
(define bar 2)
then if you load, or compile f1.scm it is exactly the same as if you had loaded or compiled a file fe.scm which contained:
(define foo 1)
(begin
(define bar 2))
which in turn is the same as if fe.scm contained:
(define foo 1)
(define bar 2)
In particular this inclusion of the files happens at macro-expansion time, which happens when the compiler runs: the object file (fasl file) produced by the compiler will include compiled definitions of foo and bar, and will not in any way depend on f2.scm or its compiled equivalent existing.
Now consider f3.scm containing:
(define foo 1)
(load "f2")
(note I have assumed that (load "f2") (as opposed to (load "f2.scm")) loads the compiled file if it can find it, and the source file if it can't: I think this is implementation-dependent).
Loading the source of this file will do the same thing as loading f1.scm: it will cause foo and bar to be defined. But compiling this file will not: it will produce a compiled file which, when it is later loaded will try to load either the source or compiled versions of f2.scm. If that file exists, at load time, then it will be loaded and the effect will be the same as the include case. If it does not exist at load time, bad things will happen. Compiling f1.scm will not cause the definitions in f2.scm to be compiled.
Depending on your background it might be worth comparing this to, say, C-family languages. What include does is what #include does: it splices in source files as they are read, and in C (as in many Scheme/Lisp systems) this happens as the files are compiled. What load does is to load code at runtime, which, in C, you would need to do by invoking the dynamic linker or something.
Historically, Lisp implementations did not offer module systems.
Large programs used load in order to run a set of instructions, the load function runs a REPL script by reading S-expressions from a file, one by one, and passing them to eval.
Include, on the other hand, is used to inline the code read from a file into the your code. It does not evaluate the code.
...replace the include or include-ci expression with a begin expression containing what was read from the files
The added 'begin' prepares the code read from the file to be evaluated sequentially.
Sources: Question quotes ,Racket docs
We are all familiar with:
#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H
...
#endif
Until recently, I have never worried about loading the same Scheme file twice (The SICP Scheme interpreter implementation changes that ...)
Is there a recommended pattern in Scheme to emulate 'include guards'? Can it be portable, or is it most likely implementation specific?
I am currently using the scm implementation, and I have come up with this so far:
(if (not (defined? my-file-included))
(begin
(define my-file-included #f)
...
)) ; include guard
So I have started pasting this pattern around all my files, but I can't say I like this very much. Besides, defined? is a keyword in scm and its argument is not evaluated: (defined? my-var) while it seems to be a normal function in guile: (defined? 'my-var) and mit-scheme won't have it.
You can write a macro to detect if the given identifier is bound or no not using syntax-case. See: http://saito.hatenablog.jp/entry/2012/09/14/010849 (it's written in Japanese but you can copy&paste the code.) Even though it uses only R6RS procedures and macros, it may not work on some implementations. (The comment of the blog post mentioning R6RS Chapter 10 Expression process.)
If you are using one of R6RS or R7RS implementations (say Guile compliant R6RS), it is better to make your including file as a library and use import.
If you want to do something like this:
#if __GUILE__
# include "foo.incl"
#else
# include "bar.incl"
#endif
then you can use cond-expand like this:
(cond-expand
(guile ...)
(else ...))
NB: cond-expand is defined in R7RS and SRFI-0.
Let's say I have a library foo in foo.scm like so:
(module foo (bar)
(import scheme)
(define (bar arg)
(+ 5 arg)))
And I have a program program.scm:
(use foo)
(display (bar 2))
Now, I compile foo and generate the import library using csc -J -library foo.scm, and then compile program with csc program.scm. Running program displays "7", as expected and everything is dandy. However, I want to load program interactively in the interpreter (csi), but now for some reason each call to a function in foo has to be prefixed with foo#, i.e. in the interpreter (foo#bar 2) works, but (bar 2) doesn't even though it works when used in a source file.
Why is this? Not only is this slightly annoying, I'm also afraid that I may have a misunderstanding of how the module system works in Chicken, so any clarification would be much appreciated.
I'm not sure what you mean by "load the program into the interpreter", but usually (use foo) should load and import the library, so performing (load "program.scm") should do just that, and all the things exported by foo should be available at toplevel.
It sounds like you somehow ended up with a situation where the library has been loaded into the running system, but hasn't been imported for use at toplevel. Just typing (use foo) (or even (import foo)) at the REPL should fix this problem.
CHICKEN's module system has been designed to allow for separate compilation, which makes cross-compilation possible. To make this work, the import library and actual implementation have been separated, but this complicates things a little, as you've discovered. This is needed because the import library may define macros that are needed at compile-time, so it needs to run on the cross-compiling host, whereas the library itself will need to be available in the cross-compilation target's architecture. We're discussing on how to simplify this for CHICKEN 5, as this is something that confuses many beginners (and sometimes advanced users, too).
I've written a sort of DSL on top of Common Lisp. The domain is quite strange and my language looks quite different from Common Lisp itself. I've put all interface into a package foo:
(defpackage :foo
(:use :common-lisp
:internal-machinery)
(:shadow :in-package
:*packages*))
Switching between packages is beyond of the language concept, so I've disabled this ability by shadowing symbols in-package and *package*. Now user (programmer) of my language will be unable to switch packages. Fine.
Obviously, I want to use Common Lisp compiler to compile programs written in this language. Function compile-file looks OK for me. But there are difficulties.
I want to compile a file as if its contents were inside of my foo package. Putting (in-package :foo) on top of every program in my prototypical language is an undesirable option.
To make things even worse, I have to compile a file inside of a function:
(in-package :internal-machinery)
(defun compile-stuff (filename)
(in-package :foo) ; it will have no effect, because
; this macro must be top level form
(compile-file filename) ; other options are omitted
(in-package :internal-machinery)) ; no way, even if it were top level
; form, in-package is shadowed
I have no idea if it's possible or not, so any help would be appreciated.
How about
(defun compile-stuff (filename)
(let ((*package* (find-package '#:foo)))
(compile-file filename)))
PS. As Rainer mentioned in a comment, if you offer REPL to the user, you are not safe from the user changing the package with (cl:in-package "CL-USER").