Quickutilβ

Lisp utilities on demand

Fork me on GitHub

How to use

Utilities, Categories, and Symbols

is centered around the idea of a utility, a self-contained piece of functionality or very related functionalities that typically solve a small, generic problem. Utilities are assigned a variety of categories, such as math or sequences. Categories can also act as micro-libraries, such as split-sequence. Finally, utilities provide symbols, which might be functions, macros, constants, etc.

While it is most often the case, it is not necessarily true that a utility corresponds to a single symbol. For example, the utility :true-false actually provides two symbols: true and false.

allows one to query for functionality based on the three above granularities, all at the same time. It queries efficiently, too. So if you want the symbol ee—the mathematical quantity e—specifically, as well as everything in the math category, it will still only load the utility containing ee once. Moreover, if you've already installed utilities, it is smart and neither recompiles nor reinstalls them.

Loading

Currently, is in beta, and not a part of Quicklisp. The latest tarball can be downloaded into a place Quicklisp can see it, and it can be loaded via:

 (ql:quickload :quickutil) 

Loading this will create two packages: quickutil-client or qtlc for all of the acquisition and management functions, and quickutil or qtl for all of the installed utilities.

Loading Utilities

Loading utilities in is done via the function qtlc:utilize:

 (qtlc:utilize
  :utilities '(:iota :riffle)
  :categories '(:alexandria)
  :symbols '(:split-sequence-if-not))

This will acquire, compile, and load all of the requested utilities and dependencies right into the image to the quickutil package.

Utilities are acquired locally, through an auxiliary, private package called quickutil-utilities. As such, there is no network dependency whatsoever, and if is up-to-date, then so will all of the utilities. This is unlike previous releases of , which acquired all utilities off of the Internet.

For convenience, there are three functions with a subset of functionality for special cases:

(qtlc:utilize-utilities '(:riffle :weave))
Install the utilities :riffle and :weave.
(qtlc:utilize-categories '(:math :alexandria))
Install everything in the categories math and alexandria.
(qtlc:utilize-symbols '(:split-sequence-if-not))
Install the utility containing the function split-sequence-if-not.

Integrating into Your Project

There are two ways to integrate utilities from into your project: adding a compile-time evaluated qtlc:utilize form to your project or generating a stand-alone utility file. It is highly recommended that you use qtlc:utilize in order to keep utilities up-to-date!

To integrate, simply add the appropriate qtlc:utilize form somewhere in the toplevel of a file in your project and wrap it in eval-when with :compile-toplevel to ensure it gets evaluated at compile time. It is common to add it to one's utilities.lisp file, which contains project-specific helper functions in addition to the utilize form.

For example, from the Qsolve project:

 (eval-when (:compile-toplevel)
  (qtlc:utilize
   :utilities '(:factorial :binomial-coefficient :mulf :divf
                :copy-array :sort-copy
                :while
                :dohash :hash-table-key-exists-

Generating a Utility File

Sometimes a project may not want to depend on compile, or a project needs to be bootstrapped without loading any ASDF systems. A lot of times, these projects have their own utils.lisp file which inadvertently duplicates common utilities. aims to manage that by generating it automatically based off of what you need.

Generating the utilities file is done with qtlc:save-utils-as, which takes the utilities, categories, and symbols that you want to save.

 (qtlc:save-utils-as "utils.lisp"
  :utilities '(:iota :riffle)
  :categories '(:alexandria)
  :symbols '(:split-sequence-if-not)
  :package "MY-PROJECT.UTILITIES")

Now, the file utils.lisp will be saved to disk and can be added to your project. This file does not depend on or have any network dependencies! It is a completely self-contained, readable, and modifiable source file. (However, we don't recommend modifying it so it can be regenerated in the future.)

To use it, simply add it as a dependency to your ASD file, or load it into the REPL. All of the utilities that you saved will be in the package quickutil or qtl.

Please note that it is not recommended that you generate a stand-alone utility file unless you have strict bootstrapping requirements or cannot use ASDF.

Specifying the Package

For projects that use utilize, having everything go into the canonical quickutil package is okay since it is managed by . However, when one creates libraries or uses dependencies, it is necessary to create or use a dedicated package for generated utilities. If project X uses a generated file, and also depends on project Y which also uses a generated file, then there is a clash between utility functions.

requires the user to specify the package in which he or she would like to put the utilities, and optionally, specify it to be created if it hasn't been already. The function save-utils-as takes a required argument :package and two extra optional keyword arguments :ensure-package and :package-nickname:

:package string
Specify that the utilities should be loaded into the package named by the string argument.
:ensure-package boolean
Ensure that the package has been created. If the package does not already exist, will create it. By default this is t.
:package-nickname string-or-nil
If a new package is created, specify that the nickname for the package should be the given string. If nil is specified, do not create a nickname. By default this is nil.

So, for example, to save the following utilities and make them usable from the package named "MY-PROJECT.UTILITIES", we issue the following command:

 (qtlc:save-utils-as "utils.lisp"
  :utilities '(:iota :riffle)
  :categories '(:alexandria)
  :symbols '(:split-sequence-if-not)
  :package "MY-PROJECT.UTILITIES"
  :ensure-package t
  :package-nickname "UTIL")

Now when this file is loaded, we will be able to use the functions from the specified package: my-project.utilities:iota or util:iota.

If we do not want to create a new package, because it was created elsewhere in your project, we can specify it not to. This is useful if you have other project-specific utility functions that you want to keep together with the generated ones.

 (qtlc:save-utils-as "utils.lisp"
  :utilities '(:iota :riffle)
  :categories '(:alexandria)
  :symbols '(:split-sequence-if-not)
  :package "MY-PROJECT.UTILITIES"
  :ensure-package nil)

Autoloading Utilities

Especially for quick REPL interactions, it is nice to be able to use utilities without explicitly loading them simply because it is faster and requires less typing. provides an optional autoload syntax, #?, which autoloads the symbol right after it. The syntax is disabled by default, and can be enabled with qtlc:enable-autoload-syntax. For example:

 > (qtlc:enable-autoload-syntax)
> (#?implode (#?shuffle (#?explode "hello")))
"lolhe"

Autoloading only acquires utilities when it needs to; already-loaded symbols are recycled.

You can permanently enable autoload syntax by loading and putting the qtlc:enable-autoload-syntax call in your Lisp's initialization file.