1
0
Fork 0
cl-sites/lispcookbook.github.io/cl-cookbook/getting-started.html

635 lines
24 KiB
HTML
Raw Normal View History

2023-10-25 11:23:21 +02:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content=
"HTML Tidy for HTML5 for Linux version 5.2.0">
<title>Getting started with Common Lisp</title>
<meta charset="utf-8">
<meta name="description" content="A collection of examples of using Common Lisp">
<meta name="viewport" content=
"width=device-width, initial-scale=1">
<link rel="icon" href=
"assets/cl-logo-blue.png"/>
<link rel="stylesheet" href=
"assets/style.css">
<script type="text/javascript" src=
"assets/highlight-lisp.js">
</script>
<script type="text/javascript" src=
"assets/jquery-3.2.1.min.js">
</script>
<script type="text/javascript" src=
"assets/jquery.toc/jquery.toc.min.js">
</script>
<script type="text/javascript" src=
"assets/toggle-toc.js">
</script>
<link rel="stylesheet" href=
"assets/github.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h1 id="title-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Getting started with Common Lisp</h1>
<div id="logo-container">
<a href="index.html">
<img id="logo" src="assets/cl-logo-blue.png"/>
</a>
<div id="searchform-container">
<form onsubmit="duckSearch()" action="javascript:void(0)">
<input id="searchField" type="text" value="" placeholder="Search...">
</form>
</div>
<div id="toc-container" class="toc-close">
<div id="toc-title">Table of Contents</div>
<ul id="toc" class="list-unstyled"></ul>
</div>
</div>
<div id="content-container">
<h1 id="title-non-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Getting started with Common Lisp</h1>
<!-- Announcement we can keep for 1 month or more. I remove it and re-add it from time to time. -->
<p class="announce">
2024-01-12 09:23:31 +01:00
📢 🤶 ⭐
<a style="font-size: 120%" href="https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPY-XMAS2023" title="This course is under a paywall on the Udemy platform. Several videos are freely available so you can judge before diving in. vindarel is (I am) the main contributor to this Cookbook."> Discover our contributor's Lisp course with this Christmas coupon.</a>
<strong>
Recently added: 18 videos on MACROS.
</strong>
2023-10-25 11:23:21 +02:00
<a style="font-size: 90%" href="https://github.com/vindarel/common-lisp-course-in-videos/">Learn more</a>.
</p>
<p class="announce-neutral">
📕 <a href="index.html#download-in-epub">Get the EPUB and PDF</a>
</p>
<div id="content"
<p>Well begin with presenting easy steps to install a development environment and to start a new Common Lisp project.</p>
<p>Want a 2-clicks install? Then get
<a href="https://shinmera.github.io/portacle/">Portacle</a>, <em>a portable and
multi-platform</em> Common Lisp environment. It ships Emacs, SBCL (the
implementation), Quicklisp (package manager), SLIME (IDE) and
Git. Its the most straightforward way to get going!</p>
<h2 id="install-an-implementation">Install an implementation</h2>
<h3 id="with-your-package-manager">With your package manager</h3>
<p>If you dont know which implementation of Common Lisp to use, try SBCL:</p>
<pre><code>apt-get install sbcl
</code></pre>
<p>Common Lisp has been standardized via an ANSI document, so it can be
implemented in different ways. See
<a href="https://en.wikipedia.org/wiki/Common_Lisp#Implementations">Wikipedias list of implementations</a>.</p>
<p>The following implementations are packaged for Debian and most other popular Linux distributions:</p>
<ul>
<li><a href="http://www.sbcl.org/">Steel Bank Common Lisp (SBCL)</a></li>
<li><a href="https://gitlab.com/embeddable-common-lisp/ecl/">Embeddable Common Lisp (ECL)</a>, which compiles to C,</li>
<li><a href="https://clisp.sourceforge.io/">CLISP</a></li>
</ul>
<p>Other well-known implementations include:</p>
<ul>
<li><a href="http://abcl.org/">ABCL</a>, to interface with the JVM,</li>
<li><a href="https://ccl.clozure.com/">ClozureCL</a>, a good implementation with very fast build times (see this <a href="http://mr.gy/blog/clozure-cl-deb.html">Debian package for Clozure CL</a>),</li>
<li><a href="https://github.com/drmeister/clasp">CLASP</a>, that interoperates with C++ libraries using LLVM for compilation to native code,</li>
<li><a href="https://franz.com/products/allegrocl/">AllegroCL</a> (proprietary)</li>
<li><a href="http://www.lispworks.com/">LispWorks</a> (proprietary)</li>
</ul>
<p>and older implementations:</p>
<ul>
<li><a href="https://gitlab.common-lisp.net/cmucl/cmucl">CMUCL</a>, originally developed at Carnegie Mellon University, from which SBCL is derived, and</li>
<li><a href="https://en.wikipedia.org/wiki/GNU_Common_Lisp">GNU Common Lisp</a></li>
<li>and there is more!</li>
</ul>
<h3 id="with-the-asdf-vm-package-manager">With the asdf-vm package manager</h3>
<p>The <a href="http://asdf-vm.com/">asdf-vm</a> tool can be used to manage a large ecosystem of runtimes and tools.</p>
<ul>
<li><a href="http://www.sbcl.org/">Steel Bank Common Lisp (SBCL)</a> is available via <a href="https://github.com/smashedtoatoms/asdf-sbcl">this plugin</a> for <a href="http://asdf-vm.com/">asdf-vm</a></li>
</ul>
<h3 id="with-roswell">With Roswell</h3>
<p><a href="https://github.com/roswell/roswell/wiki">Roswell</a> is:</p>
<ul>
<li>an implementation manager: it makes it easy to install a Common Lisp
implementation (<code>ros install ecl</code>), an exact version of an
implementation (<code>ros install sbcl/1.2.0</code>), to change the default one
being used (<code>ros use ecl</code>),</li>
<li>a scripting environment (helps to run Lisp from the shell, to get
the command line arguments,…),</li>
<li>a script installer,</li>
<li>a testing environment (to run tests, including on popular Continuous
Integration platforms),</li>
<li>a building utility (to build images and executables in a portable way).</li>
</ul>
<p>Youll find several ways of installation on its wiki (Debian package,
Windows installer, Brew/Linux Brew,…).</p>
<h3 id="with-docker">With Docker</h3>
<p>If you already know <a href="https://docs.docker.com">Docker</a>, you can get
started with Common Lisp pretty quickly. The
<a href="https://hub.docker.com/r/clfoundation/cl-devel">clfoundation/cl-devel</a>
image comes with recent versions of SBCL, CCL, ECL and ABCL, plus
Quicklisp installed in the home (<code>/home/cl</code>), so than we can
<code>ql:quickload</code> libraries straight away.</p>
<p>Docker works on GNU/Linux, Mac and Windows.</p>
<p>The following command will download the required image (around 1.0GB
compressed), put your local sources inside the Docker image where indicated,
and drop you into an SBCL REPL:</p>
<pre><code>docker run --rm -it -v /path/to/local/code:/home/cl/common-lisp/source clfoundation/cl-devel:latest sbcl
</code></pre>
<p>We still want to develop using Emacs and SLIME, so we need to connect SLIME to
the Lisp inside Docker. See
<a href="https://gitlab.common-lisp.net/cl-docker-images/slime-docker">slime-docker</a>,
which is a library that helps on setting that up.</p>
<h3 id="on-windows">On Windows</h3>
<p>All implementations above can be installed on Windows.</p>
<p><a href="https://shinmera.github.io/portacle/">Portacle</a> is multiplatform and works on Windows.</p>
<p>You can also try:</p>
<ul>
<li><a href="https://rho-emacs.sourceforge.io/">ρEmacs</a>, a preconfigured distribution of GNU Emacs specifically for Microsoft Windows. It ships with many CL implementations: CCL, SBCL, CLISP, ABCL and ECL, and also has components for other programming languages (Python, Racket, Java, C++…).</li>
<li><a href="https://github.com/sharplispers/cormanlisp">Corman Lisp</a>, for Windows XP, Windows 2000, Windows ME or Windows NT. It is fully integrated with the Win32 API, and all the Windows API functions are readily available from Lisp.</li>
</ul>
<h2 id="start-a-repl">Start a REPL</h2>
<p>Just launch the implementation executable on the command line to enter
the REPL (Read Eval Print Loop), i.e. the interactive
interpreter.</p>
<p>Quit with <code>(quit)</code> or <code>ctr-d</code> (on some implementations).</p>
<p>Here is a sample session:</p>
<pre><code>user@debian:~$ sbcl
This is SBCL 1.3.14.debian, an implementation of ANSI Common Lisp.
More information about SBCL is available at &lt;http://www.sbcl.org/&gt;.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
* (+ 1 2)
3
* (quit)
user@debian:~$
</code></pre>
<p>You can slightly enhance the REPL (the arrow keys do not work,
it has no history,…) with <code>rlwrap</code>:</p>
<pre><code>apt-get install rlwrap
</code></pre>
<p>and:</p>
<pre><code>rlwrap sbcl
</code></pre>
<p>But well setup our editor to offer a better experience instead of
working in this REPL. See <a href="editor-support.html">editor-support</a>.</p>
<p>Lisp is interactive by nature, so in case of an error we enter the
debugger. This can be annoying in certain cases, so you might want to
use SBCLs <code>--disable-debugger</code> option.</p>
<div class="info" style="background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px;">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>TIP:</strong> The CLISP implementation has a better default REPL for the
terminal (readline capabilities, completion of symbols). You can even
use <code>clisp -on-error abort</code> to have error messages without the
debugger. It's handy to try things out, but we recommend to set-up
your editor and to use SBCL or CCL.
</div>
<div class="info" style="background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px; margin-top:1em;">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>TIP:</strong>
By adding the <code>-c</code> switch to rlwrap, you can autocomplete file names.
</div>
<h2 id="libraries">Libraries</h2>
<p>Common Lisp has thousands of libraries available under a free software license. See:</p>
<ul>
<li><a href="http://quickdocs.org/">Quickdocs</a> - the library documentation hosting for CL.</li>
<li>the <a href="https://github.com/CodyReichert/awesome-cl">Awesome-cl</a> list, a
curated list of libraries.</li>
<li><a href="http://www.cliki.net/">Cliki</a>, the Common Lisp wiki.</li>
</ul>
<h3 id="some-terminology">Some terminology</h3>
<ul>
<li>
<p>In the Common Lisp world, a <strong>package</strong> is a way of grouping symbols
together and of providing encapsulation. It is similar to a C++
namespace, a Python module or a Java package.</p>
</li>
<li>
<p>A <strong>system</strong> is a collection of CL source files bundled with an .asd
file which tells how to compile and load them. There is often a
one-to-one relationship between systems and packages, but this is in
no way mandatory. A system may declare a dependency on other
systems. Systems are managed by <a href="https://common-lisp.net/project/asdf/asdf.html">ASDF</a> (Another System Definition
Facility), which offers functionalities similar to those of <code>make</code> and
<code>ld.so</code>, and has become a de facto standard.</p>
</li>
<li>
<p>A Common Lisp library or project typically consists of one or
several ASDF systems (and is distributed as one Quicklisp project).</p>
</li>
</ul>
<h3 id="install-quicklisp">Install Quicklisp</h3>
<p><a href="https://www.quicklisp.org/beta/">Quicklisp</a> is more than a package
manager, it is also a central repository (a <em>dist</em>) that ensures that
all libraries build together.</p>
<p>It provides its own <em>dist</em> but it is also possible to build our own.</p>
<p>To install it, we can either:</p>
<p>1- run this command, anywhere:</p>
<pre><code>curl -O https://beta.quicklisp.org/quicklisp.lisp
</code></pre>
<p>and enter a Lisp REPL and load this file:</p>
<pre><code>sbcl --load quicklisp.lisp
</code></pre>
<p>or</p>
<p>2- install the Debian package:</p>
<pre><code>apt-get install cl-quicklisp
</code></pre>
<p>and load it, from a REPL:</p>
<pre><code class="language-lisp">(load "/usr/share/common-lisp/source/quicklisp/quicklisp.lisp")
</code></pre>
<p>Then, in both cases, still from the REPL:</p>
<pre><code class="language-lisp">(quicklisp-quickstart:install)
</code></pre>
<p>This will create the <code>~/quicklisp/</code> directory, where Quicklisp will
maintain its state and downloaded projects.</p>
<p>If you wish, you can install Quicklisp to a different location. For instance,
to install it to a hidden folder on Unix systems:</p>
<pre><code class="language-lisp">(quicklisp-quickstart:install :path "~/.quicklisp")
</code></pre>
<p>If you want Quicklisp to always be loaded in your Lisp sessions, run
<code>(ql:add-to-init-file)</code>: this adds the right stuff to the init file of
your CL implementation. Otherwise, you have to run <code>(load
"~/quicklisp/setup.lisp")</code> in every session if you want to use
Quicklisp or any of the libraries installed through it.</p>
<p>It adds the following in your (for example) <code>~/.sbclrc</code>:</p>
<pre><code class="language-lisp">#-quicklisp
2024-01-12 09:23:31 +01:00
(let ((quicklisp-init (merge-pathnames
"quicklisp/setup.lisp"
(user-homedir-pathname))))
2023-10-25 11:23:21 +02:00
(when (probe-file quicklisp-init)
(load quicklisp-init)))
</code></pre>
<h3 id="install-libraries">Install libraries</h3>
<p>In the REPL:</p>
<pre><code class="language-lisp">(ql:quickload "system-name")
</code></pre>
<p>For example, this installs the “<a href="https://github.com/vindarel/cl-str/">str</a>” string manipulation library:</p>
<pre><code class="language-lisp">(ql:quickload "str")
</code></pre>
<p>and voilà. You can use it right away:</p>
<pre><code class="language-lisp">(str:title-case "HELLO LISP!")
</code></pre>
<div class="info" style="background-color: #e7f3fe; border-left: 6px solid #2196F3; padding: 17px; margin: 1em;">
<strong>SEE MORE:</strong> To understand the <code>package:a-symbol</code> notation, read the <a href="packages.html">packages page</a>, section "Accessing symbols from a package".
</div>
<p>We can install more than one library at once. Here we install
<a href="https://edicl.github.io/cl-ppcre/">cl-ppcre</a> for regular-expressions, and
<a href="https://alexandria.common-lisp.dev/draft/alexandria.html">Alexandria</a>,
a utility library:</p>
<pre><code class="language-lisp">(ql:quickload '("str" "cl-ppcre" "alexandria"))
</code></pre>
<p>Anytime you want to use a third-party library in your Lisp REPL, you
can run this <code>ql:quickload</code> command. It will not hit the network a second
time if it finds that the library is already installed on your file
system. Libraries are by default installed in
<code>~/quicklisp/dist/quicklisp/</code>.</p>
<p>Note also that dozens of Common Lisp libraries are packaged in
Debian. The package names usually begin with the cl- prefix (use
<code>apt-cache search --names-only "^cl-.*"</code> to list them all).</p>
<p>For example, in order to use the <code>cl-ppcre</code> library, one should first install the <code>cl-ppcre</code> package.</p>
<p>Then, in SBCL, it can be used like this:</p>
<pre><code class="language-lisp">(require "asdf")
(require "cl-ppcre")
(cl-ppcre:regex-replace "fo+" "foo bar" "frob")
</code></pre>
<p>Here we pretend we dont have Quicklisp installed and we use <code>require</code> to load a module that is available on the file system. In doubt, you can use <code>ql:quickload</code>.</p>
<p>See Quicklisps documentation for more commands. For instance, see how to upgrade or rollback your Quicklisps distribution.</p>
<h3 id="advanced-dependencies-management">Advanced dependencies management</h3>
<p>You can drop Common Lisp projects into any of those folders:</p>
<ul>
<li><code>~/quicklisp/local-projects</code></li>
<li><code>~/common-lisp</code>,</li>
<li><code>~/.local/share/common-lisp/source</code>,</li>
</ul>
<p>A library installed here is automatically available for every project.</p>
<p>For a complete list, see the values of:</p>
<pre><code class="language-lisp">(asdf/source-registry:default-user-source-registry)
</code></pre>
<p>and</p>
<pre><code class="language-lisp">asdf:*central-registry*
</code></pre>
<h4 id="providing-our-own-version-of-a-library-cloning-projects">Providing our own version of a library. Cloning projects.</h4>
<p>Given the property above, we can clone any library into the
<code>~/quicklisp/local-projects/</code> directory and it will be found by ASDF (and Quicklisp) and
available right-away:</p>
<pre><code class="language-lisp">(asdf:load-system "system")
</code></pre>
<p>or</p>
<pre><code class="language-lisp">(ql:quickload "system")
</code></pre>
<p>The practical different between the two is that <code>ql:quickload</code> first tries to
fetch the system from the Internet if it is not already installed.</p>
<p>Note that symlinks in local-projects to another location of your liking works too.</p>
<h4 id="how-to-work-with-local-versions-of-libraries">How to work with local versions of libraries</h4>
<p>If we need libraries to be installed locally, for only one project, or
in order to easily ship a list of dependencies with an application, we
can use <a href="https://github.com/fukamachi/qlot">Qlot</a> or <a href="https://clpm.dev">CLPM</a>.</p>
<p>Quicklisp also provides
<a href="https://www.quicklisp.org/beta/bundles.html">Quicklisp bundles</a>. They
are self-contained sets of systems that are exported from Quicklisp
and loadable without involving Quicklisp.</p>
<p>At last, theres
<a href="https://github.com/quicklisp/quicklisp-controller">Quicklisp controller</a>
to help us build <em>dists</em>.</p>
<h2 id="working-with-projects">Working with projects</h2>
<p>Now that we have Quicklisp and our editor ready, we can start writing
Lisp code in a file and interacting with the REPL.</p>
<p>But what if we want to work with an existing project or create a new
one, how do we proceed, whats the right sequence of <code>defpackage</code>,
what to put in the <code>.asd</code> file, how to load the project into the REPL ?</p>
<h3 id="creating-a-new-project">Creating a new project</h3>
<p>Some project builders help to scaffold the project structure. We like
<a href="https://github.com/fukamachi/cl-project">cl-project</a> that also sets
up a tests skeleton.</p>
<p>In short:</p>
<pre><code class="language-lisp">(ql:quickload "cl-project")
(cl-project:make-project #P"./path-to-project/root/")
</code></pre>
<p>it will create a directory structure like this:</p>
<pre><code>|-- my-project.asd
|-- my-project-test.asd
|-- README.markdown
|-- README.org
|-- src
| `-- my-project.lisp
`-- tests
`-- my-project.lisp
</code></pre>
<p>Where <code>my-project.asd</code> resembles this:</p>
<pre><code class="language-lisp">(asdf:defsystem "my-project"
:version "0.1.0"
:author ""
:license ""
:depends-on () ;; &lt;== list of Quicklisp dependencies
:components ((:module "src"
:components
((:file "my-project"))))
:description ""
:long-description
#.(read-file-string
(subpathname *load-pathname* "README.markdown"))
:in-order-to ((test-op (test-op "my-project-test"))))
</code></pre>
<p>and <code>src/my-project.lisp</code> this:</p>
<pre><code class="language-lisp">(defpackage footest
(:use :cl))
(in-package :footest)
</code></pre>
<ul>
<li>ASDF documentation: <a href="https://common-lisp.net/project/asdf/asdf.html#Defining-systems-with-defsystem">defining a system with defsystem</a></li>
</ul>
<h3 id="how-to-load-an-existing-project">How to load an existing project</h3>
<p>You have created a new project, or you have an existing one, and you
want to work with it on the REPL, but Quicklisp doesnt know it. How
can you do ?</p>
<p>Well first, if you create it or clone it into
one of <code>~/common-lisp</code>, <code>~/.local/share/common-lisp/source/</code> or
<code>~/quicklisp/local-projects</code>, youll be able to <code>(ql:quickload …)</code> it with no
further ado.</p>
<p>Otherwise youll need to compile and load its system definition
(<code>.asd</code>) first. In SLIME with the <code>slime-asdf</code> contrib loaded, type <code>C-c C-k</code>
(<em>slime-compile-and-load-file</em>) in the <code>.asd</code>, then you can
<code>(ql:quickload …)</code> it.</p>
<p>You can use <code>(asdf:load-asd "my-project.asd")</code> programmatically instead of <code>C-c C-k</code>.</p>
<p>Usually you want to “enter” the system in the REPL at this stage:</p>
<pre><code class="language-lisp">(in-package :my-project)
</code></pre>
<p>Lastly, you can compile or eval the sources (<code>my-project.lisp</code>) with
<code>C-c C-k</code> or <code>C-c C-c</code> (<em>slime-compile-defun</em>) in a form, and see its
result in the REPL.</p>
<p>Another solution is to use ASDFs list of known projects:</p>
<pre><code class="language-lisp">;; startup file like ~/.sbclrc
2024-01-12 09:23:31 +01:00
(pushnew "~/to/project/" asdf:*central-registry* :test #'equal)
2023-10-25 11:23:21 +02:00
</code></pre>
<p>and since ASDF is integrated into Quicklisp, we can <code>quickload</code> our project right away.</p>
<p>Happy hacking !</p>
<h2 id="more-settings">More settings</h2>
<p>You might want to set SBCLs default encoding format to utf-8:</p>
<pre><code>(setf sb-impl::*default-external-format* :utf-8)
</code></pre>
<p>You can add this to your <code>~/.sbclrc</code>.</p>
<p>If you dislike the REPL to print all symbols upcase, add this:</p>
<pre><code>(setf *print-case* :downcase)
</code></pre>
<div class="info-box warning">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>Warning:</strong> This might break the behaviour of some packages like it happened with
<a href="https://github.com/fukamachi/mito/issues/45">Mito</a>.
Avoid doing this in production.
</div>
<h2 id="see-also">See also</h2>
<ul>
<li><a href="https://github.com/vindarel/cl-cookieproject">cl-cookieproject</a> - a project skeleton for a ready-to-use project with an entry point and unit tests. With a <code>src/</code> subdirectory, some more metadata, a 5AM test suite, a way to build a binary, an example CLI args parsing, Roswell integration.</li>
<li>Source code organization, libraries and packages: <a href="https://lispmethods.com/libraries.html">https://lispmethods.com/libraries.html</a></li>
</ul>
<h2 id="credits">Credits</h2>
<ul>
<li><a href="https://wiki.debian.org/CommonLisp">https://wiki.debian.org/CommonLisp</a></li>
<li><a href="http://articulate-lisp.com/project/new-project.html">http://articulate-lisp.com/project/new-project.html</a></li>
</ul>
<p class="page-source">
Page source: <a href="https://github.com/LispCookbook/cl-cookbook/blob/master/getting-started.md">getting-started.md</a>
</p>
</div>
<script type="text/javascript">
// Don't write the TOC on the index.
if (window.location.pathname != "/cl-cookbook/") {
$("#toc").toc({
content: "#content", // will ignore the first h1 with the site+page title.
headings: "h1,h2,h3,h4"});
}
$("#two-cols + ul").css({
"column-count": "2",
});
$("#contributors + ul").css({
"column-count": "4",
});
</script>
<div>
<footer class="footer">
<hr/>
&copy; 2002&ndash;2023 the Common Lisp Cookbook Project
<div>
📹 Discover <a style="color: darkgrey; text-decoration: underline", href="https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358">vindarel's Lisp course on Udemy</a>
</div>
</footer>
</div>
<div id="toc-btn">T<br>O<br>C</div>
</div>
<script text="javascript">
HighlightLisp.highlight_auto({className: null});
</script>
<script type="text/javascript">
function duckSearch() {
var searchField = document.getElementById("searchField");
if (searchField && searchField.value) {
var query = escape("site:lispcookbook.github.io/cl-cookbook/ " + searchField.value);
window.location.href = "https://duckduckgo.com/?kj=b2&kf=-1&ko=1&q=" + query;
// https://duckduckgo.com/params
// kj=b2: blue header in results page
// kf=-1: no favicons
}
}
</script>
<script async defer data-domain="lispcookbook.github.io/cl-cookbook" src="https://plausible.io/js/plausible.js"></script>
</body>
</html>