Giter Site home page Giter Site logo

common-lisp-tweaks's Introduction

Common Lisp Tweaks

This document collects various tweaks for working with Common Lisp.

Do not hesitate to create an issue or a pull request if you have a suggestion for a new tweak, or if you have an idea how an existing tweak can be tweaked further,

Table of Contents

General Tweaks

Improve how Emacs indents code

Emacs is usually very smart about indenting Lisp code, but there is still room for improvement, especially when using very elaborate custom macros. Put the following code in your Emacs configuration to improve indentation:

;;; By default, the keyword arguments of MAKE-INSTANCE,
;;; REINITIALIZE-INSTANCE and CHANGE-CLASS are aligned with the first
;;; argument of that function.  This looks ugly and wastes screen space.
;;; With the following changes, the keyword arguments align as if the
;;; non-keyword arguments wouldn't exist.
(put 'make-instance 'common-lisp-indent-function 1)
(put 'reinitialize-instance 'common-lisp-indent-function 1)
(put 'change-class 'common-lisp-indent-function 2)

;;; Have you ever wondered how you can have your own LET, LET* or FLET
;;; indented properly?  Here's how:
(put 'dx-flet 'common-lisp-indent-function
     '((&whole 4 &rest (&whole 1 4 &lambda &body)) &body))
(put 'dx-let 'common-lisp-indent-function
     '((&whole 4 &rest (&whole 1 1 2)) &body))
(put 'dx-let* 'common-lisp-indent-function
     '((&whole 4 &rest (&whole 1 1 2)) &body))

Tell SLIME to use Clouseau for inspecting objects

Clouseau is an graphical inspector for Common Lisp. SLIME’s built-in inspector is great, but Clouseau is better (If you doubt it, try inspecting a complex number).

With this tweak, invoking the inspector will open a new window with the graphical inspector. If there is already a window with the graphical inspector, the existing window is reused.

(defun clouseau-inspect (string)
  (interactive
   (list (slime-read-from-minibuffer
          "Inspect value (evaluated): "
          (slime-sexp-at-point))))
  (let ((inspector 'cl-user::*clouseau-inspector*))
    (slime-eval-async
        `(cl:progn
          (cl:defvar ,inspector nil)
          ;; (Re)start the inspector if necessary.
          (cl:unless (cl:and (clim:application-frame-p ,inspector)
                             (clim-internals::frame-process ,inspector))
                     (cl:setf ,inspector (cl:nth-value 1 (clouseau:inspect nil :new-process t))))
          ;; Tell the inspector to visualize the correct datum.
          (cl:setf (clouseau:root-object ,inspector :run-hook-p t)
                   (cl:eval (cl:read-from-string ,string)))
          ;; Return nothing.
          (cl:values)))))

(define-key slime-prefix-map (kbd "c") 'clouseau-inspect)

For this code to work, you also need to have Clouseau loaded it your Common Lisp image. This can be achieved either by putting (ql:quickload "clouseau") into the startup file of your Common Lisp implementation, or by integrating Clouseau into a core file.

Share one startup file across multiple implementations

If you are using multiple Common Lisp implementations on a single machine, chances are you are annoyed at having to maintain one startup file for each one of them. There is a simple trick how you can keep your startup files in sync: Just create a single file, say ~/.init.lisp, put all your configuration there, and then create a symbolic link for each implementation and have it point to this file. Here is how you can create such links:

ln -sT ~/.init.lisp ~/.clisprc.lisp    # for CLISP
ln -sT ~/.init.lisp ~/.cmucl-init.lisp # for CMUCL
ln -sT ~/.init.lisp ~/.eclrc           # for ECL
ln -sT ~/.init.lisp ~/.ccl-init.lisp   # for CCL
ln -sT ~/.init.lisp ~/.sbclrc          # for SBCL
ln -sT ~/.init.lisp ~/.abclrc          # for ABCL
ln -sT ~/.init.lisp ~/.mkclrc          # for MKCL

Note: You can still put implementation-specific code in your shared startup file if you use the #+ reader macro, as in #+sbcl(setf sb-ext:*inline-expansion-limit* 100).

Customize your startup file

The behavior of a Common Lisp implementation is determined by a several special variables. There default values are not always ideal for working interactively on a REPL. Here are some suggestions for improving that:

;; Stop Lisp from SCREAMING AT YOU.
(setf *print-case* :downcase)
;; Replace very deeply nested structures by '#' when printing.
(setf *print-level* 50)
;; Replace elements of very long sequences by '...' when printing.
(setf *print-length* 200)

Another popular tweak is to globally enact a certain compiler policy. In Common Lisp, the compiler policy consists of quantities that should be optimized for, and their respective priority on a scale from zero to three. The standard optimize qualities are

NameMeaning
compilation-speedspeed of the compilation process
debugease of debugging
safetyrun-time error checking
spaceboth code size and run-time space
speedspeed of the object code

Usually, any Lisp code change these policies locally via (declare (optimize ...)) declarations, or on a per-file basis via (declaim (optimize ...)). However “it is unspecified whether or not the compile-time side-effects of a declaim persist after the file has been compiled”, so you should be careful with the latter.

Anyways, you might not want any code you compile, load, or execute to screw with your compiler policy. Luckily, SBCL has you covered and offers a way to globally enforce certain minimum and maximum values for each quantity.

A popular option for development systems is to have both safety and debugging cranked up to the highest possible value.

#+sbcl
(progn
  (sb-ext:restrict-compiler-policy 'safety 3)
  (sb-ext:restrict-compiler-policy 'debug 3))

Warning: Restricting the compiler policy in this way will affect performance quite a bit. Don’t forget this before you run any benchmarks (This has happened to me several times by now).

Improve your Quicklisp experience

Git hooks, automatic updates, …

SBCL-specific tweaks

Use a core file for faster startup

SBCL supports loading a custom core file instead of the default, empty one. Users can create custom core files where many of their most frequently used libraries are already present to speed up startup time considerably.

The only downside of using such a custom core file is that the user is now responsible for keeping the libraries therein up to date, ideally by regenerating the core file after each new Quicklisp dist update.

A core file can be created like this:

;; Ensure that Quicklisp is up to date.
(ql:update-client)
(ql:update-all-dists)

;; Load libraries that you care about
(dolist (system '("alexandria"
                  "babel"
                  "bordeaux-threads"
                  "cffi"
                  "closer-mop"
                  "cl-ppcre"
                  "cl-fad"
                  "flexi-streams"
                  "nibbles"
                  "named-readtables"
                  "split-sequence"
                  "trivial-backtrace"
                  "trivial-features"
                  "trivial-garbage"
                  "trivial-macroexpand-all"
                  "trivial-package-local-nicknames"
                  ;; ...
                  ))
  (ql:quickload system))

(uiop:dump-image "my-core")

You can also tell Emacs to use your custom core by default by adding something like this to your configuration file:

(setf slime-lisp-implementations
      '((sbcl-vanilla ("sbcl" "--dynamic-space-size" "8GB"))
        (sbcl-custom ("sbcl" "--dynamic-space-size" "8GB" "--core" "~/path/to/my-core"))))
(setf silme-default-lisp 'sbcl-custom)

Compile SBCL yourself

You know the problem: A new, exciting version of SBCL has been released. Everyone of your friends is talking about it. You desperately want those features. But your package manager is stuck in the stone age. Fret not, because compiling SBCL yourself is actually very simple:

Install dependencies

In order to compile SBCL yourself, you need an existing Lisp implementation (ideally, an older version of SBCL), Git, a shell, GNU Make and GCC. You can get this stuff with something like

apt install build-essential git sbcl

or with whatever syntax your package manager uses.

Obtain the source code

You can obtain the source code of SBCL from Github:

git clone https://github.com/sbcl/sbcl.git sbcl && cd sbcl

Usually you don’t want to build the most recent commit on the master branch, but the most recent release. All SBCL releases are tagged, so you can (and should) checkout the most recent tag:

git checkout sbcl-2.X.Y

Build SBCL

SBCL is build by a script called make.sh. You can supply some additional options to this script to customize your build. Some popular options are

  • --dynamic-space-size=8Gb for a large default heap size.
  • --prefix=$HOME/usr to put SBCL in the user’s home directory later.
  • --fancy to enable all supported enhancements.
  • --xc-host=LISP (optional) specify the Lisp implementation to use for compiling.

After building, you should run the test suite, build the documentation, and install everything. The following one-liner performs all these steps at once:

sh make.sh --dynamic-space-size=8Gb --prefix=$HOME/usr --fancy \
    && cd tests && sh run-tests.sh && cd .. \
    && cd doc/manual && make && cd ../.. \
    && sh install.sh

Note: The above command ensures that SBCL is installed in ~/usr/bin. If you want your shell to find the SBCL executable, you also need something like export PATH=$HOME/usr/bin:$PATH in your .bashrc. You can type which sbcl to check whether your shell is able to locate the correct version.

Acknowledgements

The following people have contributed to this document in some way or another:

  • Michael Fiano
  • death
  • Michał phoe Herda
  • Marco Heisig
  • Jan Moringen

common-lisp-tweaks's People

Contributors

marcoheisig avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.