In C, to make sure we don't re-include headers that are included we use the following structure:
#ifndef UTILS
#define UTILS
#include "my_utils.h"
#endif
I've broken my Lisp program into separate files; multiple files sometimes use the same file (e.g., my_utilities is used by multiple files). When I run the program, I get warnings that I am redefining things (calling load of the same file multiple times).
This would be fixed by doing something similar to #ifndef in C. What is the Common Lisp equivalent or standard method of doing this?
I am fairly new to Lisp. Let me know if there are best practices (perhaps, a different method of structuring my programs?) that I am missing.
The question you asked
The direct analogue of preprocessor conditions like #if in C is the
#+ read-time conditionalization facility.
The question you wanted to ask
To avoid multiple loading of a file, you can either use the standard
(but deprecated)
provide/require facility,
or an add-on system like ASDF.
For Common Lisp applications and libraries it is preferred to use a system management tool. Like ASDF or whatever your implementation may provide. A system is a collection of files with dependencies and various actions (load, compile, ...).
You can always check the state of the runtime and do something.
Example:
(unless (fboundp 'foobar)
(require "foo")
(load "bar"))
(unless (find-package 'foobar)
(require "foo")
(load "bar"))
PROVIDE and REQUIRE are built-in functions for exactly that. If you require a module it will be loaded, unless already provided. Unfortunately this functionality is underspecified in the standard, but implementations may provide useful functionality.
Common Lisp runtimes have a list of features on the list *features*. You can use that to advertise and check functionality.
Example:
In your library:
(push :cool-new-graphics-library cl:*features*)
In your application code:
(when (member :cool-new-graphics-library cl:*features*)
(funcall (find-symbol "DRAW-SPACE-SHIP" "CNGL")
:death-star))
Common Lisp provides a way to conditionalize that a read time. The following code will only be read when the :cool-new-graphics-library feature is present, and thus it only then will be executed later:
#+cool-new-graphics-library(cngl:draw-space-ship :death-star)
Common Lisp also allows you to express some logic:
#+(and lispworks cool-new-graphics-library)
(cngl:draw-space-ship :enterprise)
#-cool-new-graphics-library(warn "no cool graphics library available")
Note that you can force Lisp to execute code at compile-time:
(eval-when (:load-toplevel :compile-toplevel :execute)
#+(and lispworks cool-new-graphics-library)
(cngl:draw-space-ship :enterprise)
#-cool-new-graphics-library(warn "no cool graphics library available")
)
For this to work the EVAL-WHEN has to be at the toplevel in a file. That means it will not work deep in nested forms. It does work inside a toplevel PROGN,LOCALLY, MACROLET and SYMBOL-MACROLET, though.
Thus EVAL-WHEN allows you to run code which is part of the file which is currently compiled. This code than can look for loaded systems, provided modules, available functions, and more.
Related
Are compliant R7RS-small implementations allowed to impose a restriction on the number of define-library per file? Some R7RS-small implementations such as Guile 3.0.7 only allow one define-library per file. Is this a deviation from the standard, or is it allowed by R7RS-small?
In R7RS define-library is just a form, similar to library in R6RS. I don't see any allowances in either case that conforming implementations may constrain a file to contain only one such form.
But the Guile documentation has something to say on the matter. In 7.7 R7RS Support:
Happily, the syntax for R7RS modules was chosen to be compatible with R6RS, and so Guile’s documentation there applies.
In 7.7.1 Incompatibilities with the R7RS:
As the R7RS is a much less ambitious standard than the R6RS (see Guile and Scheme), it is very easy for Guile to support. As such, Guile is a fully conforming implementation of R7RS, with the exception of the occasional bug and a couple of unimplemented features....
Then in 7.6.1 Incompatibilities with the R6RS
Multiple library forms in one file are not yet supported. This is because the expansion of library sets the current module, but does not restore it. This is a bug.
Yes, I think they can (and, perhaps, should).
If you look at the formal syntax & semantics in r7rs.pdf then
A program is one or more import declarations followed by one or more commands or definitions. Commands and definitions don't include define-library.
A library is exactly one define-library form.
So from that you can conclude that a program doesn't include define-library forms, and a library includes exactly one such form.
Now that document doesn't say how all this maps into files at all, so it's up to the implementation to define that. I think it would be perfectly possible for an implementation to say that the mapping of files to library files should be 1-1, so any given library file contains exactly one library. It would also be possible to have files which contained mixtures of a program and one or more libraries, of course.
In the case where libraries are in their own files (which is obviously the more interesting case in terms of allowing reuse) something has to turn a library name into a file. And that would make it reasonably natural to put exactly one library in each file.
If it was me, I'd allow files which contain a mixture of a program and one or more libraries directly present, but for files which were just libraries I'd allow just one in each file.
I wrote a program in Racket (the source code is in a .rkt file with #lang racket at the top). I also wrote a library in (mostly) portable R7RS Scheme. Can I use the library in the program in a clean way?
My goal is for the library to be widely portable between Scheme implementations (at least the R7RS-compliant ones, ideally others as well). There is a third-party R7RS shim for Racket but as far as I can tell it requires me to type #lang r7rs at the top of my source file. I presume this #lang directive would confuse Schemes other than Racket.
Can I put the core of my library in one or more portable .scm source files and then have one .rkt file with the #lang r7rs directive that tells Racket to include the portable files somehow? Does Racket understand some kind of library definition file such as the .sld used on snow-fort?
I tried to look all over the Racket documentation but I can't find this discussed anywhere. Nor did I find a general Scheme portability FAQ or best practices document.
I managed to mix Racket and R7RS code for real work and made an example of the technique on GitHub.
Here's a copy of the readme from that repo:
The Racket R7RS Shim
Racket doesn't ship with R7RS support. It's in the third-party package
r7rs by Alexis King: https://github.com/lexi-lambda/racket-r7rs
Despite not being an official part of Racket, it worked just fine for
me (I used a moderately complex library to do HTML parsing and wrote
some farily involved string processing and tree walking on top of it,
so this is definitely useful for real work).
You can install the shim via raco pkg install r7rs. Note also that
info.rkt lists r7rs in the dependencies, which you need for Heroku
and the like.
Modules
app -- a Racket application
lib -- an R7RS library used by app
sublib -- an R7RS library used by lib
What files the modules are made of
So app needs just one file, app.rkt, like any normal Racket
module.
But lib and sublib need 3 files each. lib.scm is the Scheme
code. lib.sld is the Scheme library definition. And lib.rkt is a
Racket wrapper for it. Technically you could combine lib.sld and
lib.scm into one file but it's cleaner to have them separate. You
could also copy all your Scheme code directly into lib.rkt but then
you can't import it into other Schemes.
Note that lib.scm doesn't have an (import ...) form at the top.
The imports are inside the define-library form in lib.sld. The
define-library form uses (include ...) to include the actual code
in lib.scm.
The job of lib.rkt is just to say #lang r7rs to Racket and then
include the Scheme stuff. It first needs to (import (scheme base))
so that we can use include and export. The included .sld files
import everything else from the Scheme standard that the library
needs.
Note that lib depends on sublib but sublib is not imported by
the define-library form in lib.sld. Instead, lib.rkt has to load
lib and all its dependencies: it contains (include "sublib.sld")
in addition to the obvious (include "lib.sld").
So lib.sld imports only stuff from the Scheme standard whereas
lib.rkt imports all our custom libraries. I had to resort to this
hack because I couldn't get the Racket module finder to find sublib
if I put it in the (define-library ...) imports. I didn't try hard
at all so there may well be a way to make it work.
Mutable vs immutable lists
Racket uses immutable cons cells (made by Racket's cons, satisfies
pair?) by default whereas R7RS uses mutable cons cells (made by
Racket's mcons, satisfies mpair?). That is, when you call cons
on the Scheme side, it actually makes something that looks to Racket
as if you had called mcons on the Racket side. A mutable cons means
you can use Scheme's set-car! and set-cdr! to alter it in place,
whereas the car and cdr of an immutable cons can't be changed after
the initial cons.
By default, Racket displays lists made out of mutable conses using
{curly braces} instead of (ordinary parentheses). This will bite
you when you pass lists over the R7RS--Racket boundary. You can print
using ordinary parentheses by changing the print-mpair-curly-braces
parameter but for many things it may be easier to convert your lists
(and trees) from mutable to immutable.
I don't know whether the Racket R7RS shim allows you to make immutable
conses on the Scheme side. It would be nice to have an option for
Scheme cons to make immutable conses (in that case set-car! and
set-cdr! would cause an error, which is fine for code using only
immutable data structures).
Where to find R7RS libraries
Lots of R7RS libraries are collected by Alex Shinn at
http://snow-fort.org/
Bottom line
The upshot of all this is that you can mix R7RS and Racket with a
little work and your codebase stays pretty clean (at least for simple
cases).
I would like to use DrRacket in the same way that it works for some of the ‘legacy languages’. In particular, I would like to go through a file as if it were a sequence of commands issued to the interpreter, and not as a module.
Essentially I want to run at least one file in load-mode, but I’m not sure if it’s possible to do it using DrRacket.
Ideally, I could:
*Specify a file that sets the language and maybe loads some modules, which runs by default at startup.
*Then load a file that is not a module (and has no #lang specification) and run it.
It’d also be nice (since I want to use Scheme) if it would allow redefinitions, just as the legacy languages do.
Yes you can, and in fact, the 'legacy languages' (and 'teaching languages') are actually just implemented as DrRacket Plugins. You can remove them from your copy of DrRacket and even add new ones.
There are various ways to do this depending on if you are okay with a #lang (or #reader) saved in the file. If you're not, its still doable, you just need to use drracket:get/extend:extend-unit-frame to add your tool to DrRacket, and possibly drracket:get/extend:extend-definitions-text to easily extend the definitions window.
I won't go into the details of making a generic DrRacket plugin here, that belongs in a different question...also the DrRacket Plugins Manual has the information you need.1 I will, however, point you in the direction of how you can use DrRacket in load mode out of the box.
Check out the racket/load language. It is designed to run each expression in the top level as if you were at a REPL typing it. I find it very useful for testing the differences between Racket module and top level interactions.
Of course, if you don't make a DrRacket plugin, you will still need to put:
#lang racket/load
at the top of your file, but you otherwise get a 'legacy mode' out of the box.
1If it doesn't please continue to ask questions, and of course we always love help from anyone who is willing to contribute. <3
I'm doing some stuff with Scheme48/Scsh. What I find rather inconvenient is the lack of name completion (analogous to Guile's (ice-9 readline) or Racket's Xrepl). But before Scheme48 gets completion (if it ever does) I'd like to be able to do some introspection by hand. My question is how can you get the list of all identifiers defined/visible in the current context. If I understand correctly, Scheme has one unified namespace for variables and functions (unlike Common Lisp), so this would supply information about both. Any suggestions will be appreciated.
You want to introspect environments. I am not sure that Scheme 48 has such a feature, but its module system is perhaps the way to do it.
You might want the (interaction-environment) of R7RS. I guess that S48 is not R7RS compliant.
I am using a softerware who has a build-in scheme interpreter. Users can communicate / manipulate the software by typing command in the interpreter. And users also could load some binary file to the environment. I have write some scheme code like this:
(define test (lambda() (display "This is a test!"))) ---- d:/test.scm
And then compile it into binary file which will be loaded and excuted much faster. But the document has no information about compilation of the scheme code.
After compilation user could load the binary file by typing:
(fast-load "d:/test.bin" (the-environment))
I think the "fast-load" just do read and eval things. So does the compilation is just a encrypting process? Does anybody know about these things? Any information will be appreciated! Thanks in advance.
And there is another example: the AutoCAD system. Users can write lisp code to manipulate the AutoCAD. And user could compile the lisp code into *.fas file which will be loaded into AutoCAD. So if it is really only an encrypting process, how can I write a compiler? Is there any documents about it?
Joe
If you are strictly talking about the application's built-in interpreter (as seems to be the case based on your question), there's no standard answer. You'll need to see if the application designer built compilation into their implementation and exposed that functionality for you. If not you're out of luck.
If you were to ask about stand-alone Scheme applications or libraries, many implementations (such as Chicken) provide Scheme compilers of one sort or another (the previously-mentioned Chicken Scheme compiles to C first).
If you were asking about Common Lisp (ignoring the fact that you mention Scheme specifically in your title and question). You can use the standard function, compile-file, which produces the .fasl format you alluded to at the end of your question.