1
0
Fork 0
cl-sites/lispcookbook.github.io/cl-cookbook/getting-started.html
2023-10-25 11:23:21 +02:00

633 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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">
📹 💻
<a style="font-size: 120%" href="https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPMACROSPOWER" 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 vindarel's Lisp course in videos with this September coupon.</a>
<strong>
Recently added: 18 videos on MACROS.
</strong>
<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
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
(user-homedir-pathname))))
(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
(pushnew "~/path-to-project/root/" asdf:*central-registry* :test #'equal)
</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>