- Intro
- Basic how-tos for this repo
- Racket how-tos
SICP exercises and related code
Windows 10, Windows 11, Windows Server 2019 and 2022 should be fine.
These should be installed and the main binaries on PATH
Racket >=6.11 The installer normally uses a GUI. To run without a GUI pass /s, e.g"C:\Users\jonat\Temp\chocolatey\racket\8.11.1\racket-8.11.1-x86_64-win32-cs.exe" /S
Chocolatey can also be used
choco install racket
The script setup.bat
can be used to set up some basic
environment variables and keybindings for cmd.exe.
make build
make test
Test a given section of exercises
raco test -t chap3\sect3.3.1.rkt
This is shown under test-approaches/rackunit7, which contains these files.
double.rkt
math.rkt
Both files are #lang sicp
modules containing test
and main
sub-modules defined with module+
, which is imported by using
#%require
with only
to avoid bringing unwanted racket
definitions into scope.
Inline tests are provided via (module+ test)
. This can be used
multiple times in one file, including using forward references to
definienda, i.e. the module structure has precedence over the text
ordering.
Similarly, a main function is provided in (module+ main)
. We can
also inline the main function in fragments throughout the file if we
like.
Code reuse is performed via #%provide
and #%require
. For
example, math.rkt
requires double.rkt
and calls the double
function that it provides.
In the command-line racket REPL definitions from sub-modules can be accessed as below:
(require (submod "double.rkt" main))
Whenever we require
or #%require
racket
as below,
(#%require racket rackunit)
this brings Racket’s definitions into scope, which is liable to cause conflicts with sicp definitions (e.g. the types of lists will not match).
To avoid this we can use one of the options below.
useonly
or only-in
to restrict the imported definitions
(#%require (only racket module+))
(require (only-in racket module+))
For reference see:
- documentation for “require”, which includes
- documentation for #%require
require
expands to #%require
, a lower-level import form. A
requirement spec for #%require
is similar to one for
require
, except that the syntax is more constrained, not
composable, and not extensible.
sicp
sub-module
(module inner sicp
(define baz 1)
(#%provide baz))
(require 'inner)
#lang sicp
file
Run as below; r-run is an alias from setup.bat:
racket --lib errortrace --require file.rkt r-run file.rkt
Explanation: The errortrace library mitigates the woeful incompleteness of the default “stack traces” provided by Racket (no line numbers etc.).
https://docs.racket-lang.org/errortrace/index.html
At https://groups.google.com/g/racket-users/c/CiwfIum7d4s/m/9_4fcT4zIHIJ Robby Findler suggests using xrepl, drracket or emacs.
You can also run without errortrace:
racket chap1\ex1.09-10.rkt
This is equivalent to any of these
racket -u chap1\ex1.09-10.rkt
racket --require-script chap1\ex1.09-10.rkt
racket -t chap1\ex1.09-10.rkt -N chap1\ex1.09-10.rkt
racket --require chap1\ex1.09-10.rkt --name chap1\ex1.09-10.rkt
racket --eval '(require (file "chap1\ex1.09-10.rkt"))' --name chap1\ex1.09-10.rkt
# --name <file> sets `(find-system-path 'run-file)` to <file>
Much better, should be the default: https://docs.racket-lang.org/xrepl/index.html
# gotcha: the -i has to be first!
racket -i -u utils\sicp-utils.rkt
Assume we want to access definitions in module foo.rkt that defines x but does not provide it externally.
With xrepl$ racket
Welcome to Racket vX.X.X.
-> ,en foo.rkt
"foo.rkt"> (+ x 12)
54
$ racket
> (enter! "foo.rkt")
> x
42
$ racket -i --eval '(enter! "foo.rkt")'
https://docs.racket-lang.org/debug/index.html
(#%require debug/repl) (debug-repl)
Seems to be broken out of the box
(#%require racket/help)
usage: racket [<option> ...] <argument> ...
:
File and expression options:
:
–eval and variants
--eval <exprs>, -e <exprs> Evaluate <exprs>, print results --load <file>, -f <file> Like --eval '(load "<file>")' without printing --require <file>, -t <file> Like --eval '(require (file "<file>"))' [*] --lib <path>, -l <path> Like --eval '(require (lib "<path>"))' [*]
--name <file>, -N <file> Sets `(find-system-path 'run-file)` to <file>
Variants with “–name”
--script <file>, -r <file> Same as --load <file> --name <file> -- --require-script <file>, -u <file> Same as --require <file> --name <file> --
-m, --main Call `main` with command-line arguments, print results
:
[*] Also `require`s a `main` submodule, if any
Interaction options:
:
-i, --repl Run interactive read-eval-print loop; implies -v -n, --no-lib Skip `(require (lib "<init-lib>"))` for -i/-e/-f/-r
Configuration options:
:
-y, --make Yes, enable automatic update of compiled files -I <path> Set <init-lib> to <path> (sets language)
Meta options:
:
-- No argument following this switch is used as a switch
Default options:
:
* If only configuration options are provided, -i is added * If only configuration options are before the first argument, -u/--require-script is added * If -t/--require/-l/--lib/-p/-u/--require-script appears before the first -i/--repl/-e/--eval/-f/--load/-r/--script, --no-lib is added * <init-lib> defaults to racket/init
:
Start-up sequence:
:
1. Set `current-library-collection-paths` 2. Require `(lib "<init-lib>")` [when -i/--repl/-e/--eval/-f/--load/-r/--require, unless -n/--no-lib] 3. Evaluate/load expressions/files in order, until first error 4. Load "racketrc.rktl" [when -i] 5. Run read-eval-print loop [when -i]
Gripe: In the style of many purist computer-science languages (see also Haskell) racket defaults to the kind of global, build-from-source approach to package management that is basically a recipe for works-on-my-machine bugs.
Anyhow …
raco pkg install <package-name>
There is a system for declaring dependencies using files called
info.rkt
. raco pkg install
supports installing these
automatically.