2815 lines
122 KiB
HTML
2815 lines
122 KiB
HTML
|
|
||
|
<!DOCTYPE HTML>
|
||
|
<html lang="" >
|
||
|
<head>
|
||
|
<meta charset="UTF-8">
|
||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||
|
<title>Extra Credit: Look-up Lists and Trees · Learn Lisp The Hard Way</title>
|
||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||
|
<meta name="description" content="">
|
||
|
<meta name="generator" content="GitBook 3.2.3">
|
||
|
<meta name="author" content=""the Phoeron" Colin J.E. Lupton">
|
||
|
|
||
|
|
||
|
|
||
|
<link rel="stylesheet" href="gitbook/style.css">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<link rel="stylesheet" href="gitbook/gitbook-plugin-hints/plugin-hints.css">
|
||
|
|
||
|
|
||
|
|
||
|
<link rel="stylesheet" href="gitbook/gitbook-plugin-folding-chapters/folding-chapters.css">
|
||
|
|
||
|
|
||
|
|
||
|
<link rel="stylesheet" href="gitbook/gitbook-plugin-highlight/website.css">
|
||
|
|
||
|
|
||
|
|
||
|
<link rel="stylesheet" href="gitbook/gitbook-plugin-search/search.css">
|
||
|
|
||
|
|
||
|
|
||
|
<link rel="stylesheet" href="gitbook/gitbook-plugin-fontsettings/website.css">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<meta name="HandheldFriendly" content="true"/>
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||
|
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="gitbook/images/apple-touch-icon-precomposed-152.png">
|
||
|
<link rel="shortcut icon" href="gitbook/images/favicon.ico" type="image/x-icon">
|
||
|
|
||
|
|
||
|
<link rel="next" href="1-06-0-math.html" />
|
||
|
|
||
|
|
||
|
<link rel="prev" href="1-04-0-lists.html" />
|
||
|
|
||
|
|
||
|
</head>
|
||
|
<body>
|
||
|
|
||
|
<div class="book">
|
||
|
<div class="book-summary">
|
||
|
|
||
|
|
||
|
<div id="book-search-input" role="search">
|
||
|
<input type="text" placeholder="Type to search" />
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<nav role="navigation">
|
||
|
|
||
|
|
||
|
|
||
|
<ul class="summary">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<li class="header">LEARN LISP THE HARD WAY</li>
|
||
|
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="1.1" data-path="./">
|
||
|
|
||
|
<a href="index.html">
|
||
|
|
||
|
|
||
|
Second Draft (in-progress)
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="1.2" data-path="CHANGELOG.html">
|
||
|
|
||
|
<a href="CHANGELOG.html">
|
||
|
|
||
|
|
||
|
CHANGELOG
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="1.3" data-path="TODO.html">
|
||
|
|
||
|
<a href="TODO.html">
|
||
|
|
||
|
|
||
|
TODO
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<li class="header">PREFACE</li>
|
||
|
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="2.1" data-path="preface.html">
|
||
|
|
||
|
<a href="preface.html">
|
||
|
|
||
|
|
||
|
TANSTAAFL
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="2.2" data-path="preface-part-two.html">
|
||
|
|
||
|
<a href="preface-part-two.html">
|
||
|
|
||
|
|
||
|
The Hard Way is Easier
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="2.3" data-path="preface-part-three.html">
|
||
|
|
||
|
<a href="preface-part-three.html">
|
||
|
|
||
|
|
||
|
Who Is This Book For?
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="2.4" data-path="introduction.html">
|
||
|
|
||
|
<a href="introduction.html">
|
||
|
|
||
|
|
||
|
Lisp: A Future History
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="2.5" data-path="acknowledgements.html">
|
||
|
|
||
|
<a href="acknowledgements.html">
|
||
|
|
||
|
|
||
|
Acknowledgements
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<li class="header">PART ONE</li>
|
||
|
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="3.1" data-path="1-0-0-overview.html">
|
||
|
|
||
|
<a href="1-0-0-overview.html">
|
||
|
|
||
|
|
||
|
Grokking Lisp
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
<ul class="articles">
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="3.1.1" data-path="1-01-00-lisp-bootcamp.html">
|
||
|
|
||
|
<a href="1-01-00-lisp-bootcamp.html">
|
||
|
|
||
|
|
||
|
Common Lisp Bootcamp
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
<ul class="articles">
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="3.1.1.1" data-path="1-01-01-syntax-overview.html">
|
||
|
|
||
|
<a href="1-01-01-syntax-overview.html">
|
||
|
|
||
|
|
||
|
Syntax Overview in 5 Minutes
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.1.2" data-path="1-01-02-repl.html">
|
||
|
|
||
|
<a href="1-01-02-repl.html">
|
||
|
|
||
|
|
||
|
The REPL
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.1.3" data-path="1-01-03-expressions.html">
|
||
|
|
||
|
<a href="1-01-03-expressions.html">
|
||
|
|
||
|
|
||
|
Expressions, Parentheses, and Return Values
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.1.4" data-path="1-01-04-lists-cons-cells.html">
|
||
|
|
||
|
<a href="1-01-04-lists-cons-cells.html">
|
||
|
|
||
|
|
||
|
Lists, Cons-Cells, and Memory
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.1.5" data-path="1-01-05-symbols.html">
|
||
|
|
||
|
<a href="1-01-05-symbols.html">
|
||
|
|
||
|
|
||
|
Symbols and Namespaces
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.1.6" data-path="1-01-06-prefix-notation.html">
|
||
|
|
||
|
<a href="1-01-06-prefix-notation.html">
|
||
|
|
||
|
|
||
|
Prefix Notation
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.1.7" data-path="1-01-07-style-guide.html">
|
||
|
|
||
|
<a href="1-01-07-style-guide.html">
|
||
|
|
||
|
|
||
|
Common Lisp Style Guide
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.1.8" data-path="1-01-08-configuration.html">
|
||
|
|
||
|
<a href="1-01-08-configuration.html">
|
||
|
|
||
|
|
||
|
Configuring Your Development Environment
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2" data-path="1-02-00-input-output.html">
|
||
|
|
||
|
<a href="1-02-00-input-output.html">
|
||
|
|
||
|
|
||
|
Printing, Streams, and Strings
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
<ul class="articles">
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.1" data-path="1-02-01-strings.html">
|
||
|
|
||
|
<a href="1-02-01-strings.html">
|
||
|
|
||
|
|
||
|
Strings
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.2" data-path="1-02-02-more-strings.html">
|
||
|
|
||
|
<a href="1-02-02-more-strings.html">
|
||
|
|
||
|
|
||
|
More Strings
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.3" data-path="1-02-03-unicode.html">
|
||
|
|
||
|
<a href="1-02-03-unicode.html">
|
||
|
|
||
|
|
||
|
Unicode and Strings
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.4" data-path="1-02-04-chars.html">
|
||
|
|
||
|
<a href="1-02-04-chars.html">
|
||
|
|
||
|
|
||
|
Characters
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.5" data-path="1-02-05-more-chars.html">
|
||
|
|
||
|
<a href="1-02-05-more-chars.html">
|
||
|
|
||
|
|
||
|
More Characters
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.6" data-path="1-02-06-char-codes.html">
|
||
|
|
||
|
<a href="1-02-06-char-codes.html">
|
||
|
|
||
|
|
||
|
Character Codes
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.7" data-path="1-02-07-strings-from-chars.html">
|
||
|
|
||
|
<a href="1-02-07-strings-from-chars.html">
|
||
|
|
||
|
|
||
|
Strings from Chars
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.8" data-path="1-02-08-printing.html">
|
||
|
|
||
|
<a href="1-02-08-printing.html">
|
||
|
|
||
|
|
||
|
Printing
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.9" data-path="1-02-09-more-printing.html">
|
||
|
|
||
|
<a href="1-02-09-more-printing.html">
|
||
|
|
||
|
|
||
|
More Printing
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.10" data-path="1-02-10-prin1.html">
|
||
|
|
||
|
<a href="1-02-10-prin1.html">
|
||
|
|
||
|
|
||
|
Printing With prin1
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.11" data-path="1-02-11-princ.html">
|
||
|
|
||
|
<a href="1-02-11-princ.html">
|
||
|
|
||
|
|
||
|
Printing With princ
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.12" data-path="1-02-12-format.html">
|
||
|
|
||
|
<a href="1-02-12-format.html">
|
||
|
|
||
|
|
||
|
A Brief Introduction to Format
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.13" data-path="1-02-13-more-format.html">
|
||
|
|
||
|
<a href="1-02-13-more-format.html">
|
||
|
|
||
|
|
||
|
A Little Bit More on Format
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.14" data-path="1-02-14-pathnames.html">
|
||
|
|
||
|
<a href="1-02-14-pathnames.html">
|
||
|
|
||
|
|
||
|
Pathnames
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.15" data-path="1-02-15-streams.html">
|
||
|
|
||
|
<a href="1-02-15-streams.html">
|
||
|
|
||
|
|
||
|
Streams
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.16" data-path="1-02-16-file-streams.html">
|
||
|
|
||
|
<a href="1-02-16-file-streams.html">
|
||
|
|
||
|
|
||
|
File Streams
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.17" data-path="1-02-17-binary-streams.html">
|
||
|
|
||
|
<a href="1-02-17-binary-streams.html">
|
||
|
|
||
|
|
||
|
Binary Streams
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.18" data-path="1-02-18-prompting-users.html">
|
||
|
|
||
|
<a href="1-02-18-prompting-users.html">
|
||
|
|
||
|
|
||
|
Prompting Users
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.2.19" data-path="1-02-19-pretty-printing.html">
|
||
|
|
||
|
<a href="1-02-19-pretty-printing.html">
|
||
|
|
||
|
|
||
|
Pretty-Printing
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.3" data-path="1-03-0-getting-input-from-users.html">
|
||
|
|
||
|
<a href="1-03-0-getting-input-from-users.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Getting Input from Users
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.4" data-path="1-04-0-lists.html">
|
||
|
|
||
|
<a href="1-04-0-lists.html">
|
||
|
|
||
|
|
||
|
Lists and List-Operations
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter active" data-level="3.1.5" data-path="1-05-0-lookups-trees.html">
|
||
|
|
||
|
<a href="1-05-0-lookups-trees.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Look-up Lists and Trees
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6" data-path="1-06-0-math.html">
|
||
|
|
||
|
<a href="1-06-0-math.html">
|
||
|
|
||
|
|
||
|
Numbers and Math
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
<ul class="articles">
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.1" data-path="1-06-01-integers.html">
|
||
|
|
||
|
<a href="1-06-01-integers.html">
|
||
|
|
||
|
|
||
|
Integers
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.2" data-path="1-06-02-more-integers.html">
|
||
|
|
||
|
<a href="1-06-02-more-integers.html">
|
||
|
|
||
|
|
||
|
More Integers
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.3" data-path="1-06-03-hexadecimal-notation.html">
|
||
|
|
||
|
<a href="1-06-03-hexadecimal-notation.html">
|
||
|
|
||
|
|
||
|
Hexadecimal Integer Notation
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.4" data-path="1-06-04-octal-notation.html">
|
||
|
|
||
|
<a href="1-06-04-octal-notation.html">
|
||
|
|
||
|
|
||
|
Octal Integer Notation
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.5" data-path="1-06-05-binary-notation.html">
|
||
|
|
||
|
<a href="1-06-05-binary-notation.html">
|
||
|
|
||
|
|
||
|
Binary Integer Notation
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.6" data-path="1-06-06-ratios.html">
|
||
|
|
||
|
<a href="1-06-06-ratios.html">
|
||
|
|
||
|
|
||
|
Ratios and Rational Numbers
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.7" data-path="1-06-07-floating-point.html">
|
||
|
|
||
|
<a href="1-06-07-floating-point.html">
|
||
|
|
||
|
|
||
|
Floating-point Numbers
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.8" data-path="1-06-08-constants.html">
|
||
|
|
||
|
<a href="1-06-08-constants.html">
|
||
|
|
||
|
|
||
|
Numeric Constants
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.9" data-path="1-06-09-complex-numbers.html">
|
||
|
|
||
|
<a href="1-06-09-complex-numbers.html">
|
||
|
|
||
|
|
||
|
Complex Numbers
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.10" data-path="1-06-10-arithmetic.html">
|
||
|
|
||
|
<a href="1-06-10-arithmetic.html">
|
||
|
|
||
|
|
||
|
Arithmetic
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.11" data-path="1-06-11-more-arithmetic.html">
|
||
|
|
||
|
<a href="1-06-11-more-arithmetic.html">
|
||
|
|
||
|
|
||
|
More Arithmetic
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.12" data-path="1-06-12-even-more-arithmetic.html">
|
||
|
|
||
|
<a href="1-06-12-even-more-arithmetic.html">
|
||
|
|
||
|
|
||
|
Even More Arithmetic
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.13" data-path="1-06-13-exponents.html">
|
||
|
|
||
|
<a href="1-06-13-exponents.html">
|
||
|
|
||
|
|
||
|
Exponents
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.14" data-path="1-06-14-logarithms.html">
|
||
|
|
||
|
<a href="1-06-14-logarithms.html">
|
||
|
|
||
|
|
||
|
Logarithms
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.15" data-path="1-06-15-trigonometry.html">
|
||
|
|
||
|
<a href="1-06-15-trigonometry.html">
|
||
|
|
||
|
|
||
|
Trigonometry
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.6.16" data-path="1-06-16-psuedorandom-numbers.html">
|
||
|
|
||
|
<a href="1-06-16-psuedorandom-numbers.html">
|
||
|
|
||
|
|
||
|
Pseudo-Random Numbers
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.7" data-path="1-07-0-arrays.html">
|
||
|
|
||
|
<a href="1-07-0-arrays.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Arrays and Vectors
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.8" data-path="1-08-0-variables.html">
|
||
|
|
||
|
<a href="1-08-0-variables.html">
|
||
|
|
||
|
|
||
|
Variables, Parameters, and Constants
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.9" data-path="1-09-0-closures.html">
|
||
|
|
||
|
<a href="1-09-0-closures.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Closures
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.10" data-path="1-10-0-functions.html">
|
||
|
|
||
|
<a href="1-10-0-functions.html">
|
||
|
|
||
|
|
||
|
Functions and Macros
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.11" data-path="1-11-0-text-adventure.html">
|
||
|
|
||
|
<a href="1-11-0-text-adventure.html">
|
||
|
|
||
|
|
||
|
Extra Credit: A Simple Text Adventure
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.12" data-path="1-12-0-namespaces.html">
|
||
|
|
||
|
<a href="1-12-0-namespaces.html">
|
||
|
|
||
|
|
||
|
Namespaces, Symbols, Packages, and Systems
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.13" data-path="1-13-0-simple-web-app.html">
|
||
|
|
||
|
<a href="1-13-0-simple-web-app.html">
|
||
|
|
||
|
|
||
|
Extra Credit: A Simple Web Application
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.14" data-path="1-14-0-conditionals.html">
|
||
|
|
||
|
<a href="1-14-0-conditionals.html">
|
||
|
|
||
|
|
||
|
Conditionals
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.15" data-path="1-15-0-command-line-utility.html">
|
||
|
|
||
|
<a href="1-15-0-command-line-utility.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Command-Line Utilities
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.16" data-path="1-16-0-map-loop.html">
|
||
|
|
||
|
<a href="1-16-0-map-loop.html">
|
||
|
|
||
|
|
||
|
Mapping and Looping
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.17" data-path="1-17-0-iterate.html">
|
||
|
|
||
|
<a href="1-17-0-iterate.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Revisiting Loops with Iterate
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.18" data-path="1-18-0-format.html">
|
||
|
|
||
|
<a href="1-18-0-format.html">
|
||
|
|
||
|
|
||
|
Format Strings
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.19" data-path="1-19-0-dsl.html">
|
||
|
|
||
|
<a href="1-19-0-dsl.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Domain Specific Languages
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="3.1.20" data-path="1-20-0-review.html">
|
||
|
|
||
|
<a href="1-20-0-review.html">
|
||
|
|
||
|
|
||
|
Part One in Review
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<li class="header">PART TWO</li>
|
||
|
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="4.1" data-path="2-0-0-overview.html">
|
||
|
|
||
|
<a href="2-0-0-overview.html">
|
||
|
|
||
|
|
||
|
The Suffusion of Blue
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
<ul class="articles">
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="4.1.1" data-path="2-01-0-programming-paradigms.html">
|
||
|
|
||
|
<a href="2-01-0-programming-paradigms.html">
|
||
|
|
||
|
|
||
|
Programming Paradigms
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.2" data-path="2-02-0-regex.html">
|
||
|
|
||
|
<a href="2-02-0-regex.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Regular Expressions
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.3" data-path="2-03-0-objects-control.html">
|
||
|
|
||
|
<a href="2-03-0-objects-control.html">
|
||
|
|
||
|
|
||
|
Objects and Control Structures
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.4" data-path="2-04-0-data-persistence.html">
|
||
|
|
||
|
<a href="2-04-0-data-persistence.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Persistence and Databases
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.5" data-path="2-05-0-extended-types.html">
|
||
|
|
||
|
<a href="2-05-0-extended-types.html">
|
||
|
|
||
|
|
||
|
Extended Types
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.6" data-path="2-06-0-threads-memos-parallel.html">
|
||
|
|
||
|
<a href="2-06-0-threads-memos-parallel.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Concurrency and Memoization
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.7" data-path="2-07-0-logic-and-more-math.html">
|
||
|
|
||
|
<a href="2-07-0-logic-and-more-math.html">
|
||
|
|
||
|
|
||
|
Logic and Advanced Math
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.8" data-path="2-08-0-number-theory.html">
|
||
|
|
||
|
<a href="2-08-0-number-theory.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Number Theory
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.9" data-path="2-09-0-binary-octets-bits.html">
|
||
|
|
||
|
<a href="2-09-0-binary-octets-bits.html">
|
||
|
|
||
|
|
||
|
Binary Streams, Octet-Vectors, and Bit-Vectors
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.10" data-path="2-10-0-improved-text-adventure-engine.html">
|
||
|
|
||
|
<a href="2-10-0-improved-text-adventure-engine.html">
|
||
|
|
||
|
|
||
|
Extra Credit: An Improved Text Adventure Engine
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.11" data-path="2-11-0-conditions.html">
|
||
|
|
||
|
<a href="2-11-0-conditions.html">
|
||
|
|
||
|
|
||
|
Conditions and Error Handling
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.12" data-path="2-12-0-2d-game.html">
|
||
|
|
||
|
<a href="2-12-0-2d-game.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Write a 2D Game
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.13" data-path="2-13-0-compiler.html">
|
||
|
|
||
|
<a href="2-13-0-compiler.html">
|
||
|
|
||
|
|
||
|
The Compiler
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.14" data-path="2-14-0-tree-shaker.html">
|
||
|
|
||
|
<a href="2-14-0-tree-shaker.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Write a Tree-Shaker
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.15" data-path="2-15-0-docs-and-inspection.html">
|
||
|
|
||
|
<a href="2-15-0-docs-and-inspection.html">
|
||
|
|
||
|
|
||
|
Documentation and Inspection
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.16" data-path="2-16-0-foreign-libs.html">
|
||
|
|
||
|
<a href="2-16-0-foreign-libs.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Foreign Libraries in Lisp
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.17" data-path="2-17-0-debugging-testing.html">
|
||
|
|
||
|
<a href="2-17-0-debugging-testing.html">
|
||
|
|
||
|
|
||
|
Debugging and Unit Testing
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.18" data-path="2-18-0-ffi.html">
|
||
|
|
||
|
<a href="2-18-0-ffi.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Write a Foreign Function Interface
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.19" data-path="2-19-0-essential-libs.html">
|
||
|
|
||
|
<a href="2-19-0-essential-libs.html">
|
||
|
|
||
|
|
||
|
Essential Lisp Libraries
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.20" data-path="2-20-0-packaging-libs.html">
|
||
|
|
||
|
<a href="2-20-0-packaging-libs.html">
|
||
|
|
||
|
|
||
|
Extra Credit: Packaging Lisp Libraries
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="4.1.21" data-path="2-21-0-review.html">
|
||
|
|
||
|
<a href="2-21-0-review.html">
|
||
|
|
||
|
|
||
|
Detailed Syntax Review
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<li class="header">PART THREE</li>
|
||
|
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="5.1" data-path="3-00-00-overview.html">
|
||
|
|
||
|
<a href="3-00-00-overview.html">
|
||
|
|
||
|
|
||
|
Lisp So(u)rcery
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
<ul class="articles">
|
||
|
|
||
|
|
||
|
<li class="chapter " data-level="5.1.1" data-path="3-01-00-web-apps.html">
|
||
|
|
||
|
<a href="3-01-00-web-apps.html">
|
||
|
|
||
|
|
||
|
Real-world Web Apps
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.2" data-path="3-02-00-typesetting.html">
|
||
|
|
||
|
<a href="3-02-00-typesetting.html">
|
||
|
|
||
|
|
||
|
Typesetting
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.3" data-path="3-03-00-mobile.html">
|
||
|
|
||
|
<a href="3-03-00-mobile.html">
|
||
|
|
||
|
|
||
|
Native Mobile Applications
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.4" data-path="3-04-00-gui.html">
|
||
|
|
||
|
<a href="3-04-00-gui.html">
|
||
|
|
||
|
|
||
|
Cross-platform Desktop Applications
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.5" data-path="3-05-00-system-utils.html">
|
||
|
|
||
|
<a href="3-05-00-system-utils.html">
|
||
|
|
||
|
|
||
|
Drivers, Daemons, and System-Utilities
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.6" data-path="3-06-00-reverse-engineering.html">
|
||
|
|
||
|
<a href="3-06-00-reverse-engineering.html">
|
||
|
|
||
|
|
||
|
Reverse Engineering
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.7" data-path="3-07-00-graphics.html">
|
||
|
|
||
|
<a href="3-07-00-graphics.html">
|
||
|
|
||
|
|
||
|
Graphics Rendering
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.8" data-path="3-08-00-gaming.html">
|
||
|
|
||
|
<a href="3-08-00-gaming.html">
|
||
|
|
||
|
|
||
|
OpenGL, SDL, and 3D Game Development
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.9" data-path="3-09-00-audio.html">
|
||
|
|
||
|
<a href="3-09-00-audio.html">
|
||
|
|
||
|
|
||
|
Audio Generation and Manipulation
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.10" data-path="3-10-00-data.html">
|
||
|
|
||
|
<a href="3-10-00-data.html">
|
||
|
|
||
|
|
||
|
Data Aggregation and Analysis
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.11" data-path="3-11-00-cryptosec.html">
|
||
|
|
||
|
<a href="3-11-00-cryptosec.html">
|
||
|
|
||
|
|
||
|
Cryptography and Security
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.12" data-path="3-12-00-fintech.html">
|
||
|
|
||
|
<a href="3-12-00-fintech.html">
|
||
|
|
||
|
|
||
|
Financial Software and Crypto-Currencies
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.13" data-path="3-13-00-scientific-computing.html">
|
||
|
|
||
|
<a href="3-13-00-scientific-computing.html">
|
||
|
|
||
|
|
||
|
Scientific Computing
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.14" data-path="3-14-00-computational-physics.html">
|
||
|
|
||
|
<a href="3-14-00-computational-physics.html">
|
||
|
|
||
|
|
||
|
Computational Physics
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.15" data-path="3-15-00-quantum-computing.html">
|
||
|
|
||
|
<a href="3-15-00-quantum-computing.html">
|
||
|
|
||
|
|
||
|
Quantum Computing
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.16" data-path="3-16-00-nlp.html">
|
||
|
|
||
|
<a href="3-16-00-nlp.html">
|
||
|
|
||
|
|
||
|
Natural Language Processing
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.17" data-path="3-17-00-ai.html">
|
||
|
|
||
|
<a href="3-17-00-ai.html">
|
||
|
|
||
|
|
||
|
Artificial Intelligence
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.18" data-path="3-18-00-robotics.html">
|
||
|
|
||
|
<a href="3-18-00-robotics.html">
|
||
|
|
||
|
|
||
|
Robotics
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.19" data-path="3-19-00-space-tech.html">
|
||
|
|
||
|
<a href="3-19-00-space-tech.html">
|
||
|
|
||
|
|
||
|
Space Tech
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.20" data-path="3-20-00-neurotech.html">
|
||
|
|
||
|
<a href="3-20-00-neurotech.html">
|
||
|
|
||
|
|
||
|
Neuroscience and Thought-Controlled Computing
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.21" data-path="3-21-00-lispos.html">
|
||
|
|
||
|
<a href="3-21-00-lispos.html">
|
||
|
|
||
|
|
||
|
A Simple LispOS
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.22" data-path="3-22-00-lisp-machine.html">
|
||
|
|
||
|
<a href="3-22-00-lisp-machine.html">
|
||
|
|
||
|
|
||
|
Build Your Own Lisp Machine
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
<li class="chapter " data-level="5.1.23" data-path="3-23-00-gov-mil.html">
|
||
|
|
||
|
<a href="3-23-00-gov-mil.html">
|
||
|
|
||
|
|
||
|
Government and Military Grade Systems
|
||
|
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
</ul>
|
||
|
|
||
|
</li>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<li class="divider"></li>
|
||
|
|
||
|
<li>
|
||
|
<a href="https://www.gitbook.com" target="blank" class="gitbook-link">
|
||
|
Published with GitBook
|
||
|
</a>
|
||
|
</li>
|
||
|
</ul>
|
||
|
|
||
|
|
||
|
</nav>
|
||
|
|
||
|
|
||
|
</div>
|
||
|
|
||
|
<div class="book-body">
|
||
|
|
||
|
<div class="body-inner">
|
||
|
|
||
|
|
||
|
|
||
|
<div class="book-header" role="navigation">
|
||
|
|
||
|
|
||
|
<!-- Title -->
|
||
|
<h1>
|
||
|
<i class="fa fa-circle-o-notch fa-spin"></i>
|
||
|
<a href="index.html" >Extra Credit: Look-up Lists and Trees</a>
|
||
|
</h1>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<div class="page-wrapper" tabindex="-1" role="main">
|
||
|
<div class="page-inner">
|
||
|
|
||
|
<div id="book-search-results">
|
||
|
<div class="search-noresults">
|
||
|
|
||
|
<section class="normal markdown-section">
|
||
|
|
||
|
<h1 id="chapter-15-----extra-credit">Chapter 1.5 --- Extra Credit</h1>
|
||
|
<h2 id="look-up-lists-and-trees">Look-up Lists and Trees</h2>
|
||
|
<blockquote>
|
||
|
<p>"Take sides! Always take sides! You will sometimes be wrong—but the man who refuses to take sides must <em>always</em> be wrong."</p>
|
||
|
<footer>Robert A. Heinlein, <em>Double Star</em></footer>
|
||
|
|
||
|
</blockquote>
|
||
|
<p>In addition to the typical lists you saw throughout the exercises of the previous chapter, Lisp also has a couple special types of look-up lists that have more structure than just position. They are called Association Lists and Property Lists, or <code>alists</code> and <code>plists</code> for short. They are typically used for data and not code, because they both consist of key--value pairs; but this is Lisp, after all, so there are packages where these special data lists are repurposed as code, and later on you'll see how to do similar things yourself if you ever need or want to.</p>
|
||
|
<p>If you have never come across the concept of key--value pair data structures before, they are straightforward to use and understand---all they do is assign a value you specify to a keyword, so that you can add them to a list and get the value back later by name instead of having to remember where in the list you put the value. They are the basis for all structured data, including types such as Hash Tables, Structs, Classes, Database Tables, and more, all of which we'll be covering in this book.</p>
|
||
|
<p>This chapter will contain exercises on:</p>
|
||
|
<ul>
|
||
|
<li>Examples of ALISTS and PLISTS</li>
|
||
|
<li>Creating PLISTS</li>
|
||
|
<li>Adding items to PLISTS</li>
|
||
|
<li>Changing values in PLISTS</li>
|
||
|
<li>Removing items from PLISTS</li>
|
||
|
<li>Creating ALISTS</li>
|
||
|
<li>Adding items to ALISTS</li>
|
||
|
<li>Removing items from ALISTS</li>
|
||
|
<li>Practical size-constraints for ALISTS and PLISTS, alternate data types to look out for.</li>
|
||
|
<li>Trees</li>
|
||
|
<li>More Trees</li>
|
||
|
<li>Tries</li>
|
||
|
<li>More Tries</li>
|
||
|
<li>Why Can't I Hold All These Tries?</li>
|
||
|
<li>Object Reference</li>
|
||
|
<li>Acyclic Graphs</li>
|
||
|
</ul>
|
||
|
<h3 id="exercise-151">Exercise 1.5.1</h3>
|
||
|
<p><strong>Lookups: ALISTs and PLISTs</strong></p>
|
||
|
<p><code>alist</code>s and <code>plist</code>s are two basic ways of representing linear-lookup key--value structures. An <code>alist</code> is a list of cons cells</p>
|
||
|
<pre><code class="lang-lisp">* '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-number">2</span>) (c . <span class="hljs-number">3</span>))
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-number">2</span>) (<span class="hljs-name">C</span> . <span class="hljs-number">3</span>))
|
||
|
</code></pre>
|
||
|
<p>while a <code>plist</code> is a flat list of expressions, whose every odd element is a key and every even element is a value.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">list</span> 'a <span class="hljs-number">1</span> 'b <span class="hljs-number">2</span> 'c <span class="hljs-number">3</span>)
|
||
|
(<span class="hljs-name">A</span> <span class="hljs-number">1</span> B <span class="hljs-number">2</span> C <span class="hljs-number">3</span>)
|
||
|
</code></pre>
|
||
|
<p>Both constructs are of type <code>list</code>.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">listp</span> '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-number">2</span>) (c . <span class="hljs-number">3</span>)))
|
||
|
T
|
||
|
|
||
|
* (<span class="hljs-name">listp</span> (<span class="hljs-name">list</span> 'a <span class="hljs-number">1</span> 'b <span class="hljs-number">2</span> 'c <span class="hljs-number">3</span>))
|
||
|
T
|
||
|
</code></pre>
|
||
|
<p>Which is a double-edged blessing; any general list-processing function can transparently take <code>alist</code>s or <code>plist</code>s as arguments, but it's not easy to tell whether a particular construct is a plain <code>list</code> or a <code>plist</code>/<code>alist</code> (and there are cases where you <em>want</em> to treat them differently).</p>
|
||
|
<h3 id="exercise-152">Exercise 1.5.2</h3>
|
||
|
<p><strong>PLISTs</strong></p>
|
||
|
<p>A <code>plist</code> is just a flat list with an even number of elements. Each odd element is taken to be the key of the immediately following element.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">list</span> 'a <span class="hljs-number">1</span> 'b <span class="hljs-number">2</span>)
|
||
|
(<span class="hljs-name">A</span> <span class="hljs-number">1</span> B <span class="hljs-number">2</span>)
|
||
|
|
||
|
* (<span class="hljs-name">list</span> <span class="hljs-symbol">:foo</span> <span class="hljs-string">"a"</span> <span class="hljs-symbol">:bar</span> <span class="hljs-string">"b"</span>)
|
||
|
(<span class="hljs-symbol">:FOO</span> <span class="hljs-string">"a"</span> <span class="hljs-symbol">:BAR</span> <span class="hljs-string">"b"</span>)
|
||
|
</code></pre>
|
||
|
<p>Calling the function <code>getf</code> on a <code>plist</code> and a key will try to find that key in the <code>plist</code>. If it is found, the return value will be that keys' value.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">getf</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:foo</span> <span class="hljs-string">"a"</span> <span class="hljs-symbol">:bar</span> <span class="hljs-string">"b"</span>) <span class="hljs-symbol">:bar</span>)
|
||
|
<span class="hljs-string">"b"</span>
|
||
|
|
||
|
* (<span class="hljs-name">getf</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:foo</span> <span class="hljs-string">"a"</span> <span class="hljs-symbol">:bar</span> <span class="hljs-string">"b"</span>) <span class="hljs-symbol">:foo</span>)
|
||
|
<span class="hljs-string">"a"</span>
|
||
|
</code></pre>
|
||
|
<p>The <code>getf</code> function also takes an optional argument, <code>default</code>, which it will return if the given key is not found in the given <code>plist</code>. The default <code>default</code> is <code>NIL</code>.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">getf</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:foo</span> <span class="hljs-string">"a"</span> <span class="hljs-symbol">:bar</span> <span class="hljs-string">"b"</span>) <span class="hljs-symbol">:mumble</span>)
|
||
|
NIL
|
||
|
|
||
|
* (<span class="hljs-name">getf</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:foo</span> <span class="hljs-string">"a"</span> <span class="hljs-symbol">:bar</span> <span class="hljs-string">"b"</span>) <span class="hljs-symbol">:mumble</span> 'great-googly-moogly)
|
||
|
GREAT-GOOGLY-MOOGLY
|
||
|
</code></pre>
|
||
|
<p>Trying this on an odd-length list might give you an error, even if you specify a default value.</p>
|
||
|
<pre><code class="lang-lisp">* (getf (list :foo "a" :bar "b" :baz) :foo)
|
||
|
"a"
|
||
|
|
||
|
* (getf (list :foo "a" :bar "b" :baz) :mumble)
|
||
|
|
||
|
malformed property list: (:FOO "a" :BAR "b" :BAZ).
|
||
|
[Condition of type SIMPLE-TYPE-ERROR]
|
||
|
|
||
|
* (getf (list :foo "a" :bar "b" :baz) :mumble 'tralala)
|
||
|
|
||
|
malformed property list: (:FOO "a" :BAR "b" :BAZ).
|
||
|
[Condition of type SIMPLE-TYPE-ERROR]
|
||
|
</code></pre>
|
||
|
<h3 id="exercise-153">Exercise 1.5.3</h3>
|
||
|
<p><strong>More PLISTs</strong></p>
|
||
|
<p>Like all Cons-Cells, a <code>plist</code> can be heterogenously typed. That is, you can put many different types of things in it.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">list</span> <span class="hljs-symbol">:a</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:b</span> 'two <span class="hljs-symbol">:c</span> <span class="hljs-string">"three"</span>)
|
||
|
(<span class="hljs-symbol">:A</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:B</span> TWO <span class="hljs-symbol">:C</span> <span class="hljs-string">"three"</span>)
|
||
|
|
||
|
* (<span class="hljs-name">getf</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:a</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:b</span> 'two <span class="hljs-symbol">:c</span> <span class="hljs-string">"three"</span>) <span class="hljs-symbol">:b</span>)
|
||
|
TWO
|
||
|
|
||
|
* (<span class="hljs-name">getf</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:a</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:b</span> 'two <span class="hljs-symbol">:c</span> <span class="hljs-string">"three"</span>) <span class="hljs-symbol">:c</span>)
|
||
|
<span class="hljs-string">"three"</span>
|
||
|
</code></pre>
|
||
|
<p>This goes for the keys, as well as the values.</p>
|
||
|
<pre><code class="lang-lisp">* (list 1 :a 'two :b "three" :c)
|
||
|
(1 :A TWO :B "three" :C)
|
||
|
|
||
|
* (getf (list 1 :a 'two :b "three" :c) 1)
|
||
|
:A
|
||
|
|
||
|
* (getf (list 1 :a 'two :b "three" :c) 'two)
|
||
|
:B
|
||
|
</code></pre>
|
||
|
<p>However, be careful. <code>getf</code> tests its keys by pointer equality, and there's no way to specify otherwise. Which means that you can't <em>really</em> use compound structures as keys in a <code>plist</code>.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">getf</span> (<span class="hljs-name">list</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:a</span> 'two <span class="hljs-symbol">:b</span> <span class="hljs-string">"three"</span> <span class="hljs-symbol">:c</span>) <span class="hljs-string">"three"</span>)
|
||
|
NIL
|
||
|
</code></pre>
|
||
|
<p>Because it's a flat list, you can add keys to an existing <code>plist</code> using <code>cons</code> or <code>append</code>.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">list</span> <span class="hljs-symbol">:a</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:b</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:c</span> <span class="hljs-number">3</span>)
|
||
|
(<span class="hljs-symbol">:A</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:B</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:C</span> <span class="hljs-number">3</span>)
|
||
|
|
||
|
* (<span class="hljs-name">let</span> ((<span class="hljs-name">plist</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:a</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:b</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:c</span> <span class="hljs-number">3</span>)))
|
||
|
(<span class="hljs-name">cons</span> <span class="hljs-symbol">:d</span> (<span class="hljs-name">cons</span> <span class="hljs-number">4</span> plist)))
|
||
|
(<span class="hljs-symbol">:D</span> <span class="hljs-number">4</span> <span class="hljs-symbol">:A</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:B</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:C</span> <span class="hljs-number">3</span>)
|
||
|
|
||
|
* (<span class="hljs-name">let</span> ((<span class="hljs-name">plist</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:a</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:b</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:c</span> <span class="hljs-number">3</span>)))
|
||
|
(<span class="hljs-name">cons</span> <span class="hljs-symbol">:d</span> (<span class="hljs-name">cons</span> <span class="hljs-number">4</span> plist))
|
||
|
plist)
|
||
|
(<span class="hljs-symbol">:A</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:B</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:C</span> <span class="hljs-number">3</span>)
|
||
|
|
||
|
* (<span class="hljs-name">let</span> ((<span class="hljs-name">plist</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:a</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:b</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:c</span> <span class="hljs-number">3</span>)))
|
||
|
(<span class="hljs-name">append</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:d</span> <span class="hljs-number">4</span> <span class="hljs-symbol">:e</span> <span class="hljs-number">5</span>) plist))
|
||
|
(<span class="hljs-symbol">:D</span> <span class="hljs-number">4</span> <span class="hljs-symbol">:E</span> <span class="hljs-number">5</span> <span class="hljs-symbol">:A</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:B</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:C</span> <span class="hljs-number">3</span>)
|
||
|
|
||
|
* (<span class="hljs-name">let</span> ((<span class="hljs-name">plist</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:a</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:b</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:c</span> <span class="hljs-number">3</span>)))
|
||
|
(<span class="hljs-name">append</span> (<span class="hljs-name">list</span> <span class="hljs-symbol">:d</span> <span class="hljs-number">4</span> <span class="hljs-symbol">:e</span> <span class="hljs-number">5</span>) plist)
|
||
|
plist)
|
||
|
(<span class="hljs-symbol">:A</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:B</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:C</span> <span class="hljs-number">3</span>)
|
||
|
</code></pre>
|
||
|
<h3 id="exercise-154">Exercise 1.5.4</h3>
|
||
|
<p><strong>Even More PLISTs</strong></p>
|
||
|
<p>Its possible to mutate <code>plists</code>, as most other values, by using <code>setf</code>.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defparameter</span> *plist* (<span class="hljs-name">list</span> <span class="hljs-symbol">:a</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:b</span> 'two <span class="hljs-symbol">:c</span> <span class="hljs-string">"three"</span>))
|
||
|
*PLIST*
|
||
|
|
||
|
* (<span class="hljs-name">getf</span> *plist* <span class="hljs-symbol">:b</span>)
|
||
|
TWO
|
||
|
|
||
|
* (<span class="hljs-name">setf</span> (<span class="hljs-name">getf</span> *plist* <span class="hljs-symbol">:b</span>) 'three)
|
||
|
THREE
|
||
|
|
||
|
* (<span class="hljs-name">getf</span> *plist* <span class="hljs-symbol">:b</span>)
|
||
|
THREE
|
||
|
|
||
|
* *plist*
|
||
|
(<span class="hljs-symbol">:A</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:B</span> THREE <span class="hljs-symbol">:C</span> <span class="hljs-string">"three"</span>)
|
||
|
</code></pre>
|
||
|
<p>The key you set this way doesn't need to exist already.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">setf</span> (<span class="hljs-name">getf</span> *plist* <span class="hljs-symbol">:d</span>) <span class="hljs-number">71</span>)
|
||
|
<span class="hljs-number">71</span>
|
||
|
|
||
|
* (<span class="hljs-name">getf</span> *plist* <span class="hljs-symbol">:d</span>)
|
||
|
<span class="hljs-number">71</span>
|
||
|
</code></pre>
|
||
|
<p>but the order of new keys may surprise you.</p>
|
||
|
<pre><code class="lang-lisp">* *plist*
|
||
|
(<span class="hljs-symbol">:D</span> <span class="hljs-number">71</span> <span class="hljs-symbol">:A</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:B</span> THREE <span class="hljs-symbol">:C</span> <span class="hljs-string">"three"</span>)
|
||
|
</code></pre>
|
||
|
<p>In order to <em>remove</em> keys from a <code>plist</code>, you'd have to remove the desired key and its related value. The destructive procedure <code>remf</code> does exactly that.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">remf</span> *plist* <span class="hljs-symbol">:b</span>)
|
||
|
T
|
||
|
|
||
|
* *plist*
|
||
|
(<span class="hljs-symbol">:D</span> <span class="hljs-number">71</span> <span class="hljs-symbol">:A</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:C</span> <span class="hljs-string">"three"</span>)
|
||
|
</code></pre>
|
||
|
<h3 id="exercise-155">Exercise 1.5.5</h3>
|
||
|
<p><strong>ALISTs</strong></p>
|
||
|
<p>An <code>alist</code> is a list of Cons-Cells. The first element of each Cons-Cell is taken to be the key, while the rest is taken to be the value.</p>
|
||
|
<pre><code class="lang-lisp">* '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-number">2</span>) (c . <span class="hljs-number">3</span>))
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-number">2</span>) (<span class="hljs-name">C</span> . <span class="hljs-number">3</span>))
|
||
|
|
||
|
* (<span class="hljs-name">list</span> (<span class="hljs-name">cons</span> <span class="hljs-symbol">:foo</span> <span class="hljs-string">"a"</span>) (<span class="hljs-name">cons</span> <span class="hljs-symbol">:bar</span> <span class="hljs-string">"b"</span>))
|
||
|
((<span class="hljs-symbol">:FOO</span> . <span class="hljs-string">"a"</span>) (<span class="hljs-symbol">:BAR</span> . <span class="hljs-string">"b"</span>))
|
||
|
</code></pre>
|
||
|
<p>Calling the function <code>assoc</code> on a key and an <code>alist</code> will try to find that key in the <code>alist</code>. If it is found, the return value will be the whole Cons-Cell in question.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">assoc</span> 'b '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-number">2</span>) (c . <span class="hljs-number">3</span>)))
|
||
|
(<span class="hljs-name">B</span> . <span class="hljs-number">2</span>)
|
||
|
|
||
|
* (<span class="hljs-name">assoc</span> 'a '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-number">2</span>) (c . <span class="hljs-number">3</span>)))
|
||
|
(<span class="hljs-name">A</span> . <span class="hljs-number">1</span>)
|
||
|
</code></pre>
|
||
|
<p>Trying this on a malformed <code>alist</code>s may yield errors, though they won't be quite as specific as the ones thrown for malformed <code>plist</code>s.</p>
|
||
|
<pre><code class="lang-lisp">* (assoc 'a '((a . 1) (b . 2) c))
|
||
|
(A . 1)
|
||
|
|
||
|
* (assoc 'c '((a . 1) (b . 2) c))
|
||
|
|
||
|
The value C is not of type LIST.
|
||
|
[Condition of type TYPE-ERROR]
|
||
|
</code></pre>
|
||
|
<p>Specifically, that <code>error</code> refers to that trailing <code>c</code> in our <code>alist</code>. This is because <code>assoc</code> compares the given key with the <code>car</code> of each element in the given list. If a particular element is not a <code>list</code> (or <code>cons</code>), you can't take its <code>car</code>, which means the selector will error.</p>
|
||
|
<h3 id="exercise-156">Exercise 1.5.6</h3>
|
||
|
<p><strong>More ALISTs</strong></p>
|
||
|
<p>As with <code>plist</code>s, <code>alist</code>s may be heterogenously typed.</p>
|
||
|
<pre><code class="lang-lisp">* '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-string">"two"</span>) (c . three) (d . #(#\f #\o #\u #\r)))
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-string">"two"</span>) (<span class="hljs-name">C</span> . THREE) (<span class="hljs-name">D</span> . #(<span class="hljs-name">#</span>\f #\o #\u #\r)))
|
||
|
|
||
|
* (<span class="hljs-name">assoc</span> 'b '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-string">"two"</span>) (c . three) (d . #(#\f #\o #\u #\r))))
|
||
|
(<span class="hljs-name">B</span> . <span class="hljs-string">"two"</span>)
|
||
|
|
||
|
* (<span class="hljs-name">assoc</span> 'd '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-string">"two"</span>) (c . three) (d . #(#\f #\o #\u #\r))))
|
||
|
(<span class="hljs-name">D</span> . #(<span class="hljs-name">#</span>\f #\o #\u #\r))
|
||
|
</code></pre>
|
||
|
<p>and this again applies to both keys and values.</p>
|
||
|
<pre><code class="lang-lisp">* '((<span class="hljs-number">1</span> . a) (<span class="hljs-string">"two"</span> . b) (three . c) (#(#\f #\o #\u #\r) . d))
|
||
|
((<span class="hljs-number">1</span> . A) (<span class="hljs-string">"two"</span> . B) (<span class="hljs-name">THREE</span> . C) (<span class="hljs-name">#</span>(<span class="hljs-name">#</span>\f #\o #\u #\r) . D))
|
||
|
|
||
|
* (<span class="hljs-name">assoc</span> 'three '((<span class="hljs-number">1</span> . a) (<span class="hljs-string">"two"</span> . b) (three . c) (#(#\f #\o #\u #\r) . d)))
|
||
|
(<span class="hljs-name">THREE</span> . C)
|
||
|
|
||
|
* (<span class="hljs-name">assoc</span> <span class="hljs-number">1</span> '((<span class="hljs-number">1</span> . a) (<span class="hljs-string">"two"</span> . b) (three . c) (#(#\f #\o #\u #\r) . d)))
|
||
|
(<span class="hljs-number">1</span> . A)
|
||
|
</code></pre>
|
||
|
<p><em>Un</em>like with <code>plist</code>s, compound keys might be useful. Because <code>assoc</code> accepts a <code>test</code> (or <code>test-not</code>) argument, which lets you specify the test to run when determining key equality.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">assoc</span> <span class="hljs-string">"two"</span> '((<span class="hljs-number">1</span> . a) (<span class="hljs-string">"two"</span> . b) (three . c) (#(#\f #\o #\u #\r) . d)) <span class="hljs-symbol">:test</span> #'equal)
|
||
|
(<span class="hljs-string">"two"</span> . B)
|
||
|
|
||
|
* (<span class="hljs-name">assoc</span> #(<span class="hljs-name">#</span>\f #\o #\u #\r) '((<span class="hljs-number">1</span> . a) (<span class="hljs-string">"two"</span> . b) (three . c) (#(#\f #\o #\u #\r) . d)) <span class="hljs-symbol">:test</span> #'equalp)
|
||
|
(<span class="hljs-name">#</span>(<span class="hljs-name">#</span>\f #\o #\u #\r) . D)
|
||
|
</code></pre>
|
||
|
<p>Because <code>alist</code>s are lists of <code>cons</code> cells, you can use <code>cons</code> to functionally insert items</p>
|
||
|
<pre><code class="lang-lisp">* '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-string">"two"</span>) (c . three))
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-string">"two"</span>) (<span class="hljs-name">C</span> . THREE))
|
||
|
|
||
|
* (<span class="hljs-name">let</span> ((<span class="hljs-name">alist</span> '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-string">"two"</span>) (c . three))))
|
||
|
(<span class="hljs-name">cons</span> (<span class="hljs-name">cons</span> 'd 'four) alist))
|
||
|
((<span class="hljs-name">D</span> . FOUR) (<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-string">"two"</span>) (<span class="hljs-name">C</span> . THREE))
|
||
|
|
||
|
* (<span class="hljs-name">let</span> ((<span class="hljs-name">alist</span> '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-string">"two"</span>) (c . three))))
|
||
|
(<span class="hljs-name">cons</span> (<span class="hljs-name">cons</span> 'd 'four) alist)
|
||
|
alist)
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-string">"two"</span>) (<span class="hljs-name">C</span> . THREE))
|
||
|
</code></pre>
|
||
|
<p>Similarly, you can use the standard <code>remove</code>/<code>remove-if</code> functions on <code>alist</code>s transparently.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">remove</span> 'b '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-string">"two"</span>) (c . three)) <span class="hljs-symbol">:key</span> #'car)
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">C</span> . THREE))
|
||
|
|
||
|
* (<span class="hljs-name">remove-if</span> (<span class="hljs-name">lambda</span> (<span class="hljs-name">p</span>) (<span class="hljs-name">eq</span> 'c (<span class="hljs-name">car</span> p))) '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-string">"two"</span>) (c . three)))
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-string">"two"</span>))
|
||
|
|
||
|
* (<span class="hljs-name">remove-if</span>
|
||
|
(<span class="hljs-name">lambda</span> (<span class="hljs-name">pair</span>)
|
||
|
(<span class="hljs-name">numberp</span> (<span class="hljs-name">car</span> pair)))
|
||
|
'((a . <span class="hljs-number">1</span>) (<span class="hljs-number">1</span> . a) (b . <span class="hljs-string">"two"</span>) (<span class="hljs-number">2</span> . b) (c . three)))
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-string">"two"</span>) (<span class="hljs-name">C</span> . THREE))
|
||
|
</code></pre>
|
||
|
<h3 id="exercise-157">Exercise 1.5.7</h3>
|
||
|
<p><strong>Even More ALISTs</strong></p>
|
||
|
<p>You can mutate <code>alist</code>s, just as you can mutate almost everything else.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defparameter</span> *alist* '((a . <span class="hljs-number">1</span>) (b . <span class="hljs-number">2</span>) (c . <span class="hljs-number">3</span>)))
|
||
|
*ALIST*
|
||
|
|
||
|
* (<span class="hljs-name">setf</span> (<span class="hljs-name">cdr</span> (<span class="hljs-name">assoc</span> 'b *alist*)) <span class="hljs-number">42</span>)
|
||
|
<span class="hljs-number">42</span>
|
||
|
|
||
|
* *alist*
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-number">42</span>) (<span class="hljs-name">C</span> . <span class="hljs-number">3</span>))
|
||
|
</code></pre>
|
||
|
<p>Though, unlike with <code>plist</code>s, the key you're mutating must already exist.</p>
|
||
|
<pre><code class="lang-lisp">* (setf (cdr (assoc 'foo *alist*)) 43)
|
||
|
|
||
|
The value NIL is not of type CONS.
|
||
|
[Condition of type TYPE-ERROR]
|
||
|
</code></pre>
|
||
|
<p>It is possible to add keys to an <code>alist</code>, but you need to be more explicit about it.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">push</span> '(foo . <span class="hljs-number">43</span>) *alist*)
|
||
|
((<span class="hljs-name">FOO</span> . <span class="hljs-number">43</span>) (<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-number">42</span>) (<span class="hljs-name">C</span> . <span class="hljs-number">3</span>))
|
||
|
|
||
|
* *alist*
|
||
|
((<span class="hljs-name">FOO</span> . <span class="hljs-number">43</span>) (<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-number">42</span>) (<span class="hljs-name">C</span> . <span class="hljs-number">3</span>))
|
||
|
</code></pre>
|
||
|
<p>You can also remove keys using <code>setf</code> and the functional approaches we discussed in the previous section.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">setf</span> *alist* (<span class="hljs-name">remove</span> 'b *alist* <span class="hljs-symbol">:key</span> #'car))
|
||
|
((<span class="hljs-name">FOO</span> . <span class="hljs-number">43</span>) (<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">C</span> . <span class="hljs-number">3</span>))
|
||
|
|
||
|
* *alist*
|
||
|
((<span class="hljs-name">FOO</span> . <span class="hljs-number">43</span>) (<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">C</span> . <span class="hljs-number">3</span>))
|
||
|
</code></pre>
|
||
|
<h3 id="exercise-158">Exercise 1.5.8</h3>
|
||
|
<p><strong>Efficiency, and Alternatives to ALISTs and PLISTs</strong></p>
|
||
|
<p>We mentioned earlier that the <code>alist</code> and <code>plist</code> were both representation of linear-lookup key--value structures. This is because they both work naively. That is, doing a lookup entails traversing the entire structure and comparing each key in turn until one matches the key we're looking for...</p>
|
||
|
<pre><code class="lang-lisp">* (trace eq)
|
||
|
(EQ)
|
||
|
|
||
|
* (assoc 'b '((a . 1) (b . 2) (c . 3) (d . 4)) :test #'eq)
|
||
|
0: (EQ B A)
|
||
|
0: EQ returned NIL
|
||
|
0: (EQ B B)
|
||
|
0: EQ returned T
|
||
|
(B . 2)
|
||
|
|
||
|
* (assoc 'd '((a . 1) (b . 2) (c . 3) (d . 4)) :test #'eq)
|
||
|
0: (EQ D A)
|
||
|
0: EQ returned NIL
|
||
|
0: (EQ D B)
|
||
|
0: EQ returned NIL
|
||
|
0: (EQ D C)
|
||
|
0: EQ returned NIL
|
||
|
0: (EQ D D)
|
||
|
0: EQ returned T
|
||
|
(D . 4)
|
||
|
</code></pre>
|
||
|
<p>... or until we reach the end of the list.</p>
|
||
|
<pre><code class="lang-lisp">* (assoc 'foo '((a . 1) (b . 2) (c . 3) (d . 4)) :test #'eq)
|
||
|
0: (EQ FOO A)
|
||
|
0: EQ returned NIL
|
||
|
0: (EQ FOO B)
|
||
|
0: EQ returned NIL
|
||
|
0: (EQ FOO C)
|
||
|
0: EQ returned NIL
|
||
|
0: (EQ FOO D)
|
||
|
0: EQ returned NIL
|
||
|
NIL
|
||
|
|
||
|
* (untrace eq)
|
||
|
T
|
||
|
</code></pre>
|
||
|
<p>This is often Good Enough, but there are times when you care about lookup performance, and might be willing to sacrifice simplicity of implementation. No, we're not implementing <code>hash-table</code>s. They're already provided as part of the language (though that won't stop us later). Lets take a look at some tree structures.</p>
|
||
|
<h3 id="exercise-159">Exercise 1.5.9</h3>
|
||
|
<p><strong>Trees</strong></p>
|
||
|
<p>If we pick keys so that we can <em>sort</em> them instead of merely comparing them for equality, we could use a tree structure rather than a plain list. Though we do need to do a bit more work. A tree is typically recursively defined as either</p>
|
||
|
<ol>
|
||
|
<li>A value followed by two trees (a left branch and a right branch)</li>
|
||
|
<li>The terminal value (which marks the end of our tree)</li>
|
||
|
</ol>
|
||
|
<p>Which we can represent as things like</p>
|
||
|
<pre><code class="lang-lisp">* '((<span class="hljs-number">1</span> . a) nil nil)
|
||
|
((<span class="hljs-number">1</span> . A) NIL NIL)
|
||
|
|
||
|
* '((<span class="hljs-number">2</span> . b) ((<span class="hljs-number">1</span> . a) <span class="hljs-literal">nil</span> <span class="hljs-literal">nil</span>) ((<span class="hljs-number">3</span> . c) <span class="hljs-literal">nil</span> ((<span class="hljs-number">4</span> . d) <span class="hljs-literal">nil</span> <span class="hljs-literal">nil</span>)))
|
||
|
((<span class="hljs-number">2</span> . B) ((<span class="hljs-number">1</span> . A) NIL NIL) ((<span class="hljs-number">3</span> . C) NIL ((<span class="hljs-number">4</span> . D) NIL NIL)))
|
||
|
</code></pre>
|
||
|
<p>This is not the only possible tree representation, nor necessarily the best. We'll reserve others for later on. You can see that our "value" is a key--value pair in the style of an <code>alist</code> and our terminal value is <code>NIL</code>. Also, note that our keys are sorted. That is, everything in the left branch of a particular tree has a <em>lesser</em> key than the "value" of that tree, while everything in the right branch has a <em>greater</em> key. This is the property that will let us do faster lookups. Ideally, it will let us cut half of the remaining search space out with each comparison.</p>
|
||
|
<p>Here's <code>lookup</code>:</p>
|
||
|
<pre><code class="lang-lisp">* (defun lookup (key sorted-tree)
|
||
|
(let ((k (caar sorted-tree)))
|
||
|
(cond ((null sorted-tree) nil)
|
||
|
((> k key)
|
||
|
(lookup key (second sorted-tree)))
|
||
|
((< k key)
|
||
|
(lookup key (third sorted-tree)))
|
||
|
(t
|
||
|
(first sorted-tree)))))
|
||
|
LOOKUP
|
||
|
|
||
|
* (trace lookup)
|
||
|
(LOOKUP)
|
||
|
|
||
|
* (lookup 4 '((2 . b) ((1 . a) nil nil) ((3 . c) nil ((4 . d) nil nil))))
|
||
|
0: (LOOKUP 4 ((2 . B) ((1 . A) NIL NIL) ((3 . C) NIL ((4 . D) NIL NIL))))
|
||
|
1: (LOOKUP 4 ((3 . C) NIL ((4 . D) NIL NIL)))
|
||
|
2: (LOOKUP 4 ((4 . D) NIL NIL))
|
||
|
2: LOOKUP returned (4 . D)
|
||
|
1: LOOKUP returned (4 . D)
|
||
|
0: LOOKUP returned (4 . D)
|
||
|
(4 . D)
|
||
|
</code></pre>
|
||
|
<p>Notice that we don't compare against all of the preceding elements in order to get to ours. We only compare against 3. A tree of four key--value pairs isn't the best demonstration of this, of course.</p>
|
||
|
<h3 id="exercise-1510">Exercise 1.5.10</h3>
|
||
|
<p><strong>More Trees</strong></p>
|
||
|
<p>Since we're doing more work on trees, we may as well go <a href="https://llthw.common-lisp.dev/TODO%20link">SICP</a>-style and define the functional interface.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defun</span> tree (<span class="hljs-name">val</span> left right)
|
||
|
(<span class="hljs-name">list</span> val left right))
|
||
|
TREE
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> tree-value (<span class="hljs-name">tree</span>) (<span class="hljs-name">first</span> tree))
|
||
|
TREE-VALUE
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> tree-left (<span class="hljs-name">tree</span>) (<span class="hljs-name">second</span> tree))
|
||
|
TREE-LEFT
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> tree-right (<span class="hljs-name">tree</span>) (<span class="hljs-name">third</span> tree))
|
||
|
TREE-RIGHT
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> lookup (<span class="hljs-name">key</span> tree)
|
||
|
(<span class="hljs-name">if</span> (<span class="hljs-name">null</span> tree)
|
||
|
<span class="hljs-literal">nil</span>
|
||
|
(<span class="hljs-name">let</span> ((<span class="hljs-name">k</span> (<span class="hljs-name">car</span> (<span class="hljs-name">tree-value</span> tree))))
|
||
|
(<span class="hljs-name">cond</span> ((<span class="hljs-name">></span> k key) (<span class="hljs-name">lookup</span> key (<span class="hljs-name">tree-left</span> tree)))
|
||
|
((<span class="hljs-name"><</span> k key) (<span class="hljs-name">lookup</span> key (<span class="hljs-name">tree-right</span> tree)))
|
||
|
(<span class="hljs-name">t</span> (<span class="hljs-name">tree-value</span> tree))))))
|
||
|
<span class="hljs-comment">; STYLE-WARNING: redefining COMMON-LISP-USER::LOOKUP in DEFUN</span>
|
||
|
LOOKUP
|
||
|
</code></pre>
|
||
|
<p>Now that we have that, a naive <code>insert</code> looks like</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defun</span> insert (<span class="hljs-name">key</span> value tree)
|
||
|
(<span class="hljs-name">if</span> (<span class="hljs-name">null</span> tree)
|
||
|
(<span class="hljs-name">tree</span> (<span class="hljs-name">cons</span> key value) <span class="hljs-literal">nil</span> <span class="hljs-literal">nil</span>)
|
||
|
(<span class="hljs-name">let</span> ((<span class="hljs-name">k</span> (<span class="hljs-name">car</span> (<span class="hljs-name">tree-value</span> tree))))
|
||
|
(<span class="hljs-name">cond</span> ((<span class="hljs-name">></span> k key)
|
||
|
(<span class="hljs-name">tree</span> (<span class="hljs-name">tree-value</span> tree)
|
||
|
(<span class="hljs-name">insert</span> key value (<span class="hljs-name">tree-left</span> tree))
|
||
|
(<span class="hljs-name">tree-right</span> tree)))
|
||
|
((<span class="hljs-name"><</span> k key)
|
||
|
(<span class="hljs-name">tree</span> (<span class="hljs-name">tree-value</span> tree)
|
||
|
(<span class="hljs-name">tree-left</span> tree)
|
||
|
(<span class="hljs-name">insert</span> key value (<span class="hljs-name">tree-right</span> tree))))
|
||
|
(<span class="hljs-name">t</span> tree)))))
|
||
|
INSERT
|
||
|
</code></pre>
|
||
|
<p>We can use that insert on this specially-ordered <code>alist</code> to give us a reasonably balanced tree.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defparameter</span> *lst* '((<span class="hljs-number">5</span> . e) (<span class="hljs-number">3</span> . c) (<span class="hljs-number">4</span> . d) (<span class="hljs-number">2</span> . b) (<span class="hljs-number">1</span> . a) (<span class="hljs-number">7</span> . g) (<span class="hljs-number">6</span> . f) (<span class="hljs-number">8</span> . h) (<span class="hljs-number">9</span> . i) (<span class="hljs-number">10</span> . j)))
|
||
|
*LST*
|
||
|
|
||
|
* (<span class="hljs-name">reduce</span>
|
||
|
(<span class="hljs-name">lambda</span> (<span class="hljs-name">memo</span> pair)
|
||
|
(<span class="hljs-name">insert</span> (<span class="hljs-name">car</span> pair) (<span class="hljs-name">cdr</span> pair) memo))
|
||
|
*lst* <span class="hljs-symbol">:initial-value</span> <span class="hljs-literal">nil</span>)
|
||
|
((<span class="hljs-number">5</span> . E) ((<span class="hljs-number">3</span> . C) ((<span class="hljs-number">2</span> . B) ((<span class="hljs-number">1</span> . A) NIL NIL) NIL) ((<span class="hljs-number">4</span> . D) NIL NIL))
|
||
|
((<span class="hljs-number">7</span> . G) ((<span class="hljs-number">6</span> . F) NIL NIL) ((<span class="hljs-number">8</span> . H) NIL ((<span class="hljs-number">9</span> . I) NIL ((<span class="hljs-number">10</span> . J) NIL NIL)))))
|
||
|
|
||
|
* (<span class="hljs-name">defparameter</span> *tree*
|
||
|
(<span class="hljs-name">reduce</span>
|
||
|
(<span class="hljs-name">lambda</span> (<span class="hljs-name">memo</span> pair)
|
||
|
(<span class="hljs-name">insert</span> (<span class="hljs-name">car</span> pair) (<span class="hljs-name">cdr</span> pair) memo))
|
||
|
*lst* <span class="hljs-symbol">:initial-value</span> <span class="hljs-literal">nil</span>))
|
||
|
</code></pre>
|
||
|
<p>And, just so that we're comparing like-for-like, here's a recursive definition of <code>assoc</code></p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defun</span> rec-assoc (<span class="hljs-name">key</span> alist)
|
||
|
(<span class="hljs-name">cond</span> ((<span class="hljs-name">null</span> alist) <span class="hljs-literal">nil</span>)
|
||
|
((<span class="hljs-name">eq</span> key (<span class="hljs-name">caar</span> alist)) (<span class="hljs-name">car</span> alist))
|
||
|
(<span class="hljs-name">t</span> (<span class="hljs-name">rec-assoc</span> key (<span class="hljs-name">cdr</span> alist)))))
|
||
|
REC-ASSOC
|
||
|
</code></pre>
|
||
|
<p>Now, lets compare lookup steps involved.</p>
|
||
|
<pre><code class="lang-lisp">* (trace lookup rec-assoc)
|
||
|
(LOOKUP REC-ASSOC)
|
||
|
|
||
|
* (rec-assoc 9 *lst*)
|
||
|
0: (REC-ASSOC 9
|
||
|
((5 . E) (3 . C) (4 . D) (2 . B) (1 . A) (7 . G) (6 . F)
|
||
|
(8 . H) (9 . I) (10 . J)))
|
||
|
1: (REC-ASSOC 9
|
||
|
((3 . C) (4 . D) (2 . B) (1 . A) (7 . G) (6 . F) (8 . H)
|
||
|
(9 . I) (10 . J)))
|
||
|
2: (REC-ASSOC 9
|
||
|
((4 . D) (2 . B) (1 . A) (7 . G) (6 . F) (8 . H) (9 . I)
|
||
|
(10 . J)))
|
||
|
3: (REC-ASSOC 9
|
||
|
((2 . B) (1 . A) (7 . G) (6 . F) (8 . H) (9 . I) (10 . J)))
|
||
|
4: (REC-ASSOC 9 ((1 . A) (7 . G) (6 . F) (8 . H) (9 . I) (10 . J)))
|
||
|
5: (REC-ASSOC 9 ((7 . G) (6 . F) (8 . H) (9 . I) (10 . J)))
|
||
|
6: (REC-ASSOC 9 ((6 . F) (8 . H) (9 . I) (10 . J)))
|
||
|
7: (REC-ASSOC 9 ((8 . H) (9 . I) (10 . J)))
|
||
|
8: (REC-ASSOC 9 ((9 . I) (10 . J)))
|
||
|
8: REC-ASSOC returned (9 . I)
|
||
|
7: REC-ASSOC returned (9 . I)
|
||
|
6: REC-ASSOC returned (9 . I)
|
||
|
5: REC-ASSOC returned (9 . I)
|
||
|
4: REC-ASSOC returned (9 . I)
|
||
|
3: REC-ASSOC returned (9 . I)
|
||
|
2: REC-ASSOC returned (9 . I)
|
||
|
1: REC-ASSOC returned (9 . I)
|
||
|
0: REC-ASSOC returned (9 . I)
|
||
|
(9 . I)
|
||
|
|
||
|
* (lookup 9 *tree*)
|
||
|
0: (LOOKUP 9
|
||
|
((5 . E)
|
||
|
((3 . C) ((2 . B) ((1 . A) NIL NIL) NIL) ((4 . D) NIL NIL))
|
||
|
((7 . G) ((6 . F) NIL NIL)
|
||
|
((8 . H) NIL ((9 . I) NIL ((10 . J) NIL NIL))))))
|
||
|
1: (LOOKUP 9
|
||
|
((7 . G) ((6 . F) NIL NIL)
|
||
|
((8 . H) NIL ((9 . I) NIL ((10 . J) NIL NIL)))))
|
||
|
2: (LOOKUP 9 ((8 . H) NIL ((9 . I) NIL ((10 . J) NIL NIL))))
|
||
|
3: (LOOKUP 9 ((9 . I) NIL ((10 . J) NIL NIL)))
|
||
|
3: LOOKUP returned (9 . I)
|
||
|
2: LOOKUP returned (9 . I)
|
||
|
1: LOOKUP returned (9 . I)
|
||
|
0: LOOKUP returned (9 . I)
|
||
|
(9 . I)
|
||
|
|
||
|
* (untrace lookup rec-assoc)
|
||
|
T
|
||
|
</code></pre>
|
||
|
<p>The tree structure saves us a bit of work in a situation like this. And, if we can arrange for our lookup tree to be balanced or almost balanced, we'll save <em>more</em> work the bigger our data-set becomes.</p>
|
||
|
<h3 id="exercise-1511">Exercise 1.5.11</h3>
|
||
|
<p><strong>Tries</strong></p>
|
||
|
<p>If we can pick keys so that they're not merely sortable, but also <em>decomposable</em>, we can save a bit more time and space by using Tries <em>(As an aside, "Tree" and "Trie" are pronounced the same way. This is doubly annoying because, as you'll see in a moment, a Trie is a kind of Tree. So you can't even disambiguate by saying things like "Trie, the data structure". You'll sometimes hear Tries referred to as "Prefix trees", which may or may not help the situation)</em>.</p>
|
||
|
<p>A Trie is a value and a (possibly empty) dictionary of key parts to Tries. Which can be represented as:</p>
|
||
|
<pre><code class="lang-lisp">* '(nil nil)
|
||
|
(<span class="hljs-name">NIL</span> NIL)
|
||
|
|
||
|
* '(nil ((#\o <span class="hljs-literal">nil</span> ((#\n <span class="hljs-string">"activated; not off"</span> ((#\e <span class="hljs-string">"the english name for the numeral 1"</span> NIL)))))))
|
||
|
(<span class="hljs-name">NIL</span>
|
||
|
((<span class="hljs-name">#</span>\o NIL
|
||
|
((<span class="hljs-name">#</span>\n <span class="hljs-string">"activated; not off"</span>
|
||
|
((<span class="hljs-name">#</span>\e <span class="hljs-string">"the english name for the numeral 1"</span>)))))))
|
||
|
|
||
|
* '(nil ((<span class="hljs-number">1</span> <span class="hljs-literal">nil</span> ((<span class="hljs-number">2</span> <span class="hljs-literal">nil</span> ((<span class="hljs-number">3</span> <span class="hljs-string">"ah ah ah."</span> <span class="hljs-literal">nil</span>)))))))
|
||
|
(<span class="hljs-name">NIL</span> ((<span class="hljs-number">1</span> NIL ((<span class="hljs-number">2</span> NIL ((<span class="hljs-number">3</span> <span class="hljs-string">"ah ah ah."</span> NIL)))))))
|
||
|
|
||
|
* '(nil
|
||
|
((this <span class="hljs-literal">nil</span>
|
||
|
((sentence <span class="hljs-literal">nil</span>
|
||
|
((is <span class="hljs-literal">nil</span>
|
||
|
((a <span class="hljs-literal">nil</span> ((key <span class="hljs-string">"This sentence is a key"</span> <span class="hljs-literal">nil</span>)))
|
||
|
(not <span class="hljs-literal">nil</span> ((a <span class="hljs-literal">nil</span> ((key <span class="hljs-string">"This sentence is NOT a key"</span> <span class="hljs-literal">nil</span>)))))
|
||
|
(meaningless <span class="hljs-literal">t</span> <span class="hljs-literal">nil</span>)))))))))
|
||
|
(<span class="hljs-name">NIL</span>
|
||
|
((<span class="hljs-name">THIS</span> NIL
|
||
|
((<span class="hljs-name">SENTENCE</span> NIL
|
||
|
((<span class="hljs-name">IS</span> NIL
|
||
|
((<span class="hljs-name">A</span> NIL ((<span class="hljs-name">KEY</span> <span class="hljs-string">"This sentence is a key"</span> NIL)))
|
||
|
(<span class="hljs-name">NOT</span> NIL ((<span class="hljs-name">A</span> NIL ((<span class="hljs-name">KEY</span> <span class="hljs-string">"This sentence is NOT a key"</span> NIL)))))
|
||
|
(<span class="hljs-name">MEANINGLESS</span> T NIL)))))))))
|
||
|
</code></pre>
|
||
|
<p>Looking up a key in a Trie means taking the decomposed key, and looking up each key part level-wise.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defun</span> trie-lookup (<span class="hljs-name">key-parts</span> trie)
|
||
|
(<span class="hljs-name">if</span> (<span class="hljs-name">null</span> key-parts)
|
||
|
(<span class="hljs-name">first</span> trie)
|
||
|
(<span class="hljs-name">let</span> ((<span class="hljs-name">next</span> (<span class="hljs-name">cdr</span> (<span class="hljs-name">assoc</span> (<span class="hljs-name">car</span> key-parts) (<span class="hljs-name">second</span> trie)))))
|
||
|
(<span class="hljs-name">when</span> next
|
||
|
(<span class="hljs-name">trie-lookup</span> (<span class="hljs-name">cdr</span> key-parts) next)))))
|
||
|
TRIE-LOOKUP
|
||
|
|
||
|
* (<span class="hljs-name">defparameter</span> *trie*
|
||
|
'(nil ((#\o <span class="hljs-literal">nil</span> ((#\n <span class="hljs-string">"activated; not off"</span> ((#\e <span class="hljs-string">"the english name for the numeral 1"</span> NIL))))))))
|
||
|
*TRIE*
|
||
|
|
||
|
* (<span class="hljs-name">trie-lookup</span> '(#\o #\n) *trie*)
|
||
|
<span class="hljs-string">"activated; not off"</span>
|
||
|
|
||
|
* (<span class="hljs-name">trie-lookup</span> '(#\o #\n #\e) *trie*)
|
||
|
<span class="hljs-string">"the english name for the numeral 1"</span>
|
||
|
|
||
|
* (<span class="hljs-name">trie-lookup</span> '(#\o #\n #\e #\i #\r #\o #\s) *trie*)
|
||
|
NIL
|
||
|
|
||
|
* (<span class="hljs-name">trie-lookup</span> '(#\t #\w #\o) *trie*)
|
||
|
NIL
|
||
|
</code></pre>
|
||
|
<p>The idea here is that any common prefixes among keys are collapsed, and that some extra data about a particular sequence is held as the <code>value</code>. The best casefor a lookup is a key that shares no prefix with anything in the Trie. The worst case is a key that shares a long prefix, since we need to traverse the entire prefix before discovering the absence.</p>
|
||
|
<h3 id="exercise-1512">Exercise 1.5.12</h3>
|
||
|
<p><strong>More Tries</strong></p>
|
||
|
<p>So lets go explicit-interface-style on this problem.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defun</span> trie (<span class="hljs-name">val</span> map)
|
||
|
(<span class="hljs-name">list</span> val map))
|
||
|
TRIE
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> empty-trie ()
|
||
|
(<span class="hljs-name">trie</span> <span class="hljs-literal">nil</span> <span class="hljs-literal">nil</span>))
|
||
|
EMPTY-TRIE
|
||
|
|
||
|
* (<span class="hljs-name">empty-trie</span>)
|
||
|
(<span class="hljs-name">NIL</span> NIL)
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> trie-value (<span class="hljs-name">trie</span>)
|
||
|
(<span class="hljs-name">first</span> trie))
|
||
|
TRIE-VALUE
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> trie-table (<span class="hljs-name">trie</span>)
|
||
|
(<span class="hljs-name">second</span> trie))
|
||
|
TRIE-TABLE
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> trie-assoc (<span class="hljs-name">key-part</span> trie)
|
||
|
(<span class="hljs-name">cdr</span> (<span class="hljs-name">assoc</span> key-part (<span class="hljs-name">trie-table</span> trie))))
|
||
|
TRIE-ASSOC
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> trie-lookup (<span class="hljs-name">key-parts</span> trie)
|
||
|
(<span class="hljs-name">if</span> (<span class="hljs-name">null</span> key-parts)
|
||
|
(<span class="hljs-name">trie-value</span> trie)
|
||
|
(<span class="hljs-name">let</span> ((<span class="hljs-name">next</span> (<span class="hljs-name">trie-assoc</span> (<span class="hljs-name">first</span> key-parts) trie)))
|
||
|
(<span class="hljs-name">when</span> next
|
||
|
(<span class="hljs-name">trie-lookup</span> (<span class="hljs-name">rest</span> key-parts) next)))))
|
||
|
</code></pre>
|
||
|
<p>Those are the basic getters. And nothing really fancy has been said yet. You can see why I'd leave them out for the initial pass based on their trivial nature. Insertion is less trivial to implement, but still conceptually simple.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defun</span> trie-alist-insert (<span class="hljs-name">k</span> trie alist)
|
||
|
(<span class="hljs-name">cons</span> (<span class="hljs-name">cons</span> k trie)
|
||
|
(<span class="hljs-name">remove</span> k alist <span class="hljs-symbol">:key</span> #'car)))
|
||
|
TRIE-ALIST-INSERT
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> trie-insert (<span class="hljs-name">key</span> value trie)
|
||
|
(<span class="hljs-name">if</span> key
|
||
|
(<span class="hljs-name">let*</span> ((<span class="hljs-name">k</span> (<span class="hljs-name">first</span> key))
|
||
|
(<span class="hljs-name">next</span> (<span class="hljs-name">trie-assoc</span> k trie)))
|
||
|
(<span class="hljs-name">trie</span> (<span class="hljs-name">trie-value</span> trie)
|
||
|
(<span class="hljs-name">trie-alist-insert</span>
|
||
|
k
|
||
|
(<span class="hljs-name">trie-insert</span>
|
||
|
(<span class="hljs-name">rest</span> key) value
|
||
|
(<span class="hljs-name">or</span> next (<span class="hljs-name">trie</span> <span class="hljs-literal">nil</span> <span class="hljs-literal">nil</span>)))
|
||
|
(<span class="hljs-name">trie-table</span> trie))))
|
||
|
(<span class="hljs-name">trie</span> value (<span class="hljs-name">trie-table</span> trie))))
|
||
|
TRIE-INSERT
|
||
|
|
||
|
* (<span class="hljs-name">trie-insert</span> (<span class="hljs-name">coerce</span> <span class="hljs-string">"once"</span> 'list) <span class="hljs-string">"one time, and one time only"</span> *trie*)
|
||
|
(<span class="hljs-name">NIL</span>
|
||
|
((<span class="hljs-name">#</span>\o NIL
|
||
|
((<span class="hljs-name">#</span>\n <span class="hljs-string">"activated; not off"</span>
|
||
|
((<span class="hljs-name">#</span>\c NIL ((<span class="hljs-name">#</span>\e <span class="hljs-string">"one time, and one time only"</span> NIL)))
|
||
|
(<span class="hljs-name">#</span>\e <span class="hljs-string">"the english name for the numeral 1"</span> NIL)))))))
|
||
|
</code></pre>
|
||
|
<p>In order to insert a new value, associated with a particular key, we traverse that keys' parts and either recur to the next level of the <code>trie</code> by looking up the current part, or freshly insert that part into the current <code>trie</code> table. If we run out of key to traverse, we insert the new value, replacing an existing one if necessary.</p>
|
||
|
<pre><code class="lang-lisp">* *trie*
|
||
|
(<span class="hljs-name">NIL</span>
|
||
|
((<span class="hljs-name">#</span>\o NIL
|
||
|
((<span class="hljs-name">#</span>\n <span class="hljs-string">"activated; not off"</span>
|
||
|
((<span class="hljs-name">#</span>\e <span class="hljs-string">"the english name for the numeral 1"</span> NIL)))))))
|
||
|
|
||
|
* (<span class="hljs-name">trie-insert</span> (<span class="hljs-name">coerce</span> <span class="hljs-string">"on"</span> 'list) <span class="hljs-string">"switched on"</span> *trie*)
|
||
|
(<span class="hljs-name">NIL</span>
|
||
|
((<span class="hljs-name">#</span>\o NIL
|
||
|
((<span class="hljs-name">#</span>\n <span class="hljs-string">"switched on"</span>
|
||
|
((<span class="hljs-name">#</span>\e <span class="hljs-string">"the english name for the numeral 1"</span> NIL)))))))
|
||
|
</code></pre>
|
||
|
<p>Though of course, as always, we're not doing this replacement destructively.</p>
|
||
|
<pre><code class="lang-lisp">* *trie*
|
||
|
(<span class="hljs-name">NIL</span>
|
||
|
((<span class="hljs-name">#</span>\o NIL
|
||
|
((<span class="hljs-name">#</span>\n <span class="hljs-string">"activated; not off"</span>
|
||
|
((<span class="hljs-name">#</span>\e <span class="hljs-string">"the english name for the numeral 1"</span> NIL)))))))
|
||
|
</code></pre>
|
||
|
<p>Now, lets do the same comparison we did earlier in the Trees section.</p>
|
||
|
<pre><code>* (defun rec-string-assoc (key alist)
|
||
|
(cond ((null alist) nil)
|
||
|
((string= key (caar alist)) (car alist))
|
||
|
(t (rec-string-assoc key (cdr alist)))))
|
||
|
|
||
|
* (defparameter *alist*
|
||
|
'(("p" . "the 16th letter of the English alphabet")
|
||
|
("pea" . "the small spherical seed or the seed-pod of the pod fruit Pisum sativum")
|
||
|
("peanut" . "a plant species in the legume family")
|
||
|
("peanuts" . "plural of peanut; syndicated comic strip started in 1950")
|
||
|
("peanut butter" . "a creamy delight commonly used in sandwiches")
|
||
|
("on" . "activated; not off")
|
||
|
("one" . "the English name for the numeral 1")
|
||
|
("ones" . "plural of 'one'")
|
||
|
("once" . "one time, and one time only")))
|
||
|
|
||
|
* (defparameter *trie*
|
||
|
(reduce
|
||
|
(lambda (memo pair)
|
||
|
(trie-insert
|
||
|
(coerce (car pair) 'list)
|
||
|
(cdr pair)
|
||
|
memo))
|
||
|
*alist* :initial-value (empty-trie)))
|
||
|
*TRIE*
|
||
|
|
||
|
* (trace rec-string-assoc trie-lookup)
|
||
|
(REC-STRING-ASSOC TRIE-LOOKUP)
|
||
|
|
||
|
* (trie-lookup (coerce "once" 'list) *trie*)
|
||
|
0: (TRIE-LOOKUP (#\o #\n #\c #\e)
|
||
|
(NIL
|
||
|
((#\o NIL
|
||
|
((#\n "activated; not off"
|
||
|
((#\c NIL ((#\e "one time, and one time only" NIL)))
|
||
|
(#\e "the English name for the numeral 1"
|
||
|
((#\s "plural of 'one'" NIL)))))))
|
||
|
(#\p "the 16th letter of the English alphabet"
|
||
|
((#\e NIL
|
||
|
((#\a
|
||
|
"the small spherical seed or the seed-pod of the pod fruit Pisum sativum"
|
||
|
((#\n NIL
|
||
|
((#\u NIL
|
||
|
((#\t "a plant species in the legume family"
|
||
|
((#\ NIL
|
||
|
((#\b NIL
|
||
|
((#\u NIL
|
||
|
((#\t NIL
|
||
|
((#\t NIL
|
||
|
((#\e NIL
|
||
|
((#\r
|
||
|
"a creamy delight commonly used in sandwiches"
|
||
|
NIL)))))))))))))
|
||
|
(#\s
|
||
|
"plural of peanut; syndicated comic strip started in 1950"
|
||
|
NIL))))))))))))))))
|
||
|
1: (TRIE-LOOKUP (#\n #\c #\e)
|
||
|
(NIL
|
||
|
((#\n "activated; not off"
|
||
|
((#\c NIL ((#\e "one time, and one time only" NIL)))
|
||
|
(#\e "the English name for the numeral 1"
|
||
|
((#\s "plural of 'one'" NIL))))))))
|
||
|
2: (TRIE-LOOKUP (#\c #\e)
|
||
|
("activated; not off"
|
||
|
((#\c NIL ((#\e "one time, and one time only" NIL)))
|
||
|
(#\e "the English name for the numeral 1"
|
||
|
((#\s "plural of 'one'" NIL))))))
|
||
|
3: (TRIE-LOOKUP (#\e) (NIL ((#\e "one time, and one time only" NIL))))
|
||
|
4: (TRIE-LOOKUP NIL ("one time, and one time only" NIL))
|
||
|
4: TRIE-LOOKUP returned "one time, and one time only"
|
||
|
3: TRIE-LOOKUP returned "one time, and one time only"
|
||
|
2: TRIE-LOOKUP returned "one time, and one time only"
|
||
|
1: TRIE-LOOKUP returned "one time, and one time only"
|
||
|
0: TRIE-LOOKUP returned "one time, and one time only"
|
||
|
"one time, and one time only"
|
||
|
|
||
|
* (rec-string-assoc "once" *alist*)
|
||
|
0: (REC-STRING-ASSOC "once"
|
||
|
(("p" . "the 16th letter of the English alphabet")
|
||
|
("pea"
|
||
|
. "the small spherical seed or the seed-pod of the pod fruit Pisum sativum")
|
||
|
("peanut" . "a plant species in the legume family")
|
||
|
("peanuts"
|
||
|
. "plural of peanut; syndicated comic strip started in 1950")
|
||
|
("peanut butter"
|
||
|
. "a creamy delight commonly used in sandwiches")
|
||
|
("on" . "activated; not off")
|
||
|
("one" . "the English name for the numeral 1")
|
||
|
("ones" . "plural of 'one'")
|
||
|
("once" . "one time, and one time only")))
|
||
|
1: (REC-STRING-ASSOC "once"
|
||
|
(("pea"
|
||
|
. "the small spherical seed or the seed-pod of the pod fruit Pisum sativum")
|
||
|
("peanut" . "a plant species in the legume family")
|
||
|
("peanuts"
|
||
|
. "plural of peanut; syndicated comic strip started in 1950")
|
||
|
("peanut butter"
|
||
|
. "a creamy delight commonly used in sandwiches")
|
||
|
("on" . "activated; not off")
|
||
|
("one" . "the English name for the numeral 1")
|
||
|
("ones" . "plural of 'one'")
|
||
|
("once" . "one time, and one time only")))
|
||
|
2: (REC-STRING-ASSOC "once"
|
||
|
(("peanut" . "a plant species in the legume family")
|
||
|
("peanuts"
|
||
|
. "plural of peanut; syndicated comic strip started in 1950")
|
||
|
("peanut butter"
|
||
|
. "a creamy delight commonly used in sandwiches")
|
||
|
("on" . "activated; not off")
|
||
|
("one" . "the English name for the numeral 1")
|
||
|
("ones" . "plural of 'one'")
|
||
|
("once" . "one time, and one time only")))
|
||
|
3: (REC-STRING-ASSOC "once"
|
||
|
(("peanuts"
|
||
|
. "plural of peanut; syndicated comic strip started in 1950")
|
||
|
("peanut butter"
|
||
|
. "a creamy delight commonly used in sandwiches")
|
||
|
("on" . "activated; not off")
|
||
|
("one" . "the English name for the numeral 1")
|
||
|
("ones" . "plural of 'one'")
|
||
|
("once" . "one time, and one time only")))
|
||
|
4: (REC-STRING-ASSOC "once"
|
||
|
(("peanut butter"
|
||
|
. "a creamy delight commonly used in sandwiches")
|
||
|
("on" . "activated; not off")
|
||
|
("one" . "the English name for the numeral 1")
|
||
|
("ones" . "plural of 'one'")
|
||
|
("once" . "one time, and one time only")))
|
||
|
5: (REC-STRING-ASSOC "once"
|
||
|
(("on" . "activated; not off")
|
||
|
("one"
|
||
|
. "the English name for the numeral 1")
|
||
|
("ones" . "plural of 'one'")
|
||
|
("once" . "one time, and one time only")))
|
||
|
6: (REC-STRING-ASSOC "once"
|
||
|
(("one"
|
||
|
. "the English name for the numeral 1")
|
||
|
("ones" . "plural of 'one'")
|
||
|
("once" . "one time, and one time only")))
|
||
|
7: (REC-STRING-ASSOC "once"
|
||
|
(("ones" . "plural of 'one'")
|
||
|
("once" . "one time, and one time only")))
|
||
|
8: (REC-STRING-ASSOC "once"
|
||
|
(("once"
|
||
|
. "one time, and one time only")))
|
||
|
8: REC-STRING-ASSOC returned
|
||
|
("once" . "one time, and one time only")
|
||
|
7: REC-STRING-ASSOC returned
|
||
|
("once" . "one time, and one time only")
|
||
|
6: REC-STRING-ASSOC returned
|
||
|
("once" . "one time, and one time only")
|
||
|
5: REC-STRING-ASSOC returned
|
||
|
("once" . "one time, and one time only")
|
||
|
4: REC-STRING-ASSOC returned ("once" . "one time, and one time only")
|
||
|
3: REC-STRING-ASSOC returned ("once" . "one time, and one time only")
|
||
|
2: REC-STRING-ASSOC returned ("once" . "one time, and one time only")
|
||
|
1: REC-STRING-ASSOC returned ("once" . "one time, and one time only")
|
||
|
0: REC-STRING-ASSOC returned ("once" . "one time, and one time only")
|
||
|
("once" . "one time, and one time only")
|
||
|
|
||
|
* (untrace rec-string-assoc trie-lookup)
|
||
|
T
|
||
|
</code></pre><p>As you can see, we've got a similar situation here. When using a Trie to store our keys, we can essentially ignore groups of values for the purposes of doing a lookup. Which lets us do lookups in much better than linear time.</p>
|
||
|
<h3 id="exercise-1513">Exercise 1.5.13</h3>
|
||
|
<p><strong>Even More Tries</strong></p>
|
||
|
<p>Completely apart from basic lookup performance, which is good but not all-important, Tries let us compute completions fairly cheaply. In the definition of <code>trie-lookup</code> we've already seen, walking the trie is conflated with getting a particular value out...</p>
|
||
|
<pre><code class="lang-lisp">(<span class="hljs-name">defun</span> trie-lookup (<span class="hljs-name">key-parts</span> trie)
|
||
|
(<span class="hljs-name">if</span> (<span class="hljs-name">null</span> key-parts)
|
||
|
(<span class="hljs-name">trie-value</span> trie)
|
||
|
(<span class="hljs-name">let</span> ((<span class="hljs-name">next</span> (<span class="hljs-name">trie-assoc</span> (<span class="hljs-name">first</span> key-parts) trie)))
|
||
|
(<span class="hljs-name">when</span> next
|
||
|
(<span class="hljs-name">trie-lookup</span> (<span class="hljs-name">rest</span> key-parts) next)))))
|
||
|
</code></pre>
|
||
|
<p>...but it doesn't have to be.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defun</span> trie-walk (<span class="hljs-name">key-parts</span> trie)
|
||
|
(<span class="hljs-name">if</span> (<span class="hljs-name">null</span> key-parts)
|
||
|
trie
|
||
|
(<span class="hljs-name">let</span> ((<span class="hljs-name">next</span> (<span class="hljs-name">trie-assoc</span> (<span class="hljs-name">first</span> key-parts) trie)))
|
||
|
(<span class="hljs-name">when</span> next
|
||
|
(<span class="hljs-name">trie-walk</span> (<span class="hljs-name">rest</span> key-parts) next)))))
|
||
|
TRIE-WALK
|
||
|
|
||
|
* (<span class="hljs-name">trie-walk</span> (<span class="hljs-name">coerce</span> <span class="hljs-string">"on"</span> 'list) *trie*)
|
||
|
(<span class="hljs-string">"activated; not off"</span>
|
||
|
((<span class="hljs-name">#</span>\c NIL ((<span class="hljs-name">#</span>\e <span class="hljs-string">"one time, and one time only"</span> NIL)))
|
||
|
(<span class="hljs-name">#</span>\e <span class="hljs-string">"the English name for the numeral 1"</span> ((<span class="hljs-name">#</span>\s <span class="hljs-string">"plural of 'one'"</span> NIL)))))
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> trie-lookup (<span class="hljs-name">key-parts</span> trie)
|
||
|
(<span class="hljs-name">trie-value</span> (<span class="hljs-name">trie-walk</span> key-parts trie)))
|
||
|
TRIE-LOOKUP
|
||
|
</code></pre>
|
||
|
<p>With a definition of <code>trie-walk</code> so decoupled, we can now do the pre-order traversal and come out with a list of contained keys that start with the components we pass in.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defun</span> trie-completions (<span class="hljs-name">key-parts</span> trie)
|
||
|
(<span class="hljs-name">labels</span> ((<span class="hljs-name">recur</span> (<span class="hljs-name">path</span> trie)
|
||
|
(<span class="hljs-name">let</span> ((<span class="hljs-name">rest</span> (<span class="hljs-name">loop</span> for (<span class="hljs-name">k</span> . sub-trie) in (<span class="hljs-name">trie-table</span> trie)
|
||
|
append (<span class="hljs-name">recur</span> (<span class="hljs-name">append</span> path (<span class="hljs-name">list</span> k)) sub-trie)) ))
|
||
|
(<span class="hljs-name">if</span> (<span class="hljs-name">trie-value</span> trie)
|
||
|
(<span class="hljs-name">cons</span> path rest)
|
||
|
rest))))
|
||
|
(<span class="hljs-name">recur</span> key-parts (<span class="hljs-name">trie-walk</span> key-parts trie))))
|
||
|
TRIE-COMPLETIONS
|
||
|
|
||
|
* (<span class="hljs-name">trie-completions</span> (<span class="hljs-name">coerce</span> <span class="hljs-string">"on"</span> 'list) *trie*)
|
||
|
((<span class="hljs-name">#</span>\o #\n) (<span class="hljs-name">#</span>\o #\n #\c #\e) (<span class="hljs-name">#</span>\o #\n #\e) (<span class="hljs-name">#</span>\o #\n #\e #\s))
|
||
|
</code></pre>
|
||
|
<p>There are a couple of other ways we can vary Trie implementations. Firstly, we can change the representation of our <code>trie-map</code>. In all of the above examples, they're <code>alist</code>s, but that's not a requirement. It might be reasonable to make them <code>hash-table</code>s, or objects, or Trees, or even sub-Tries depending on our situation. Secondly, except for a few brief examples back in exercise 1.5.11, we've been dealing with Tries whose keys are strings and decompose into characters. Other options are possible; for example the top level might be a phrase that decomposes into words, or numbers that decompose into bits.</p>
|
||
|
<p>We won't be investigating any of the variations at the moment though; that might happen in later chapters.</p>
|
||
|
<h3 id="exercise-1514">Exercise 1.5.14</h3>
|
||
|
<p><strong>Hash Tables</strong></p>
|
||
|
<p>Hash Tables are the standard constant-time lookup structure you're familiar with from other languages.</p>
|
||
|
<pre><code class="lang-lisp">* (make-hash-table)
|
||
|
#<HASH-TABLE :TEST EQL :COUNT 0 {1003F59933}>
|
||
|
</code></pre>
|
||
|
<p>Unlike the other table structures we've taken a look at, there isn't really a non-destructive way to interact with a Hash Table. If you want to insert keys, you mutate the argument. You <em>could</em> copy the table out manually and add your new key to the copy, but that makes insertion take linear time. And you still have to do it manually; you don't get it for free the way you might with a Trie or <code>alist</code>.</p>
|
||
|
<pre><code class="lang-lisp">* (let ((hash (make-hash-table)))
|
||
|
(setf (gethash 'a hash) 1
|
||
|
(gethash 'b hash) 2
|
||
|
(gethash 'c hash) 3)
|
||
|
hash)
|
||
|
#<HASH-TABLE :TEST EQL :COUNT 3 {1004099983}>
|
||
|
|
||
|
* (let ((hash (make-hash-table)))
|
||
|
(setf (gethash 'a hash) 1
|
||
|
(gethash 'b hash) 2
|
||
|
(gethash 'c hash) 3)
|
||
|
(gethash 'b hash))
|
||
|
2
|
||
|
T
|
||
|
</code></pre>
|
||
|
<p>There's no functional way to remove keys from hash tables either, other than the mentioned table-copying approach. Removing a key mutates the argument.</p>
|
||
|
<pre><code class="lang-lisp">* (let ((hash (make-hash-table)))
|
||
|
(setf (gethash 'a hash) 1
|
||
|
(gethash 'b hash) 2
|
||
|
(gethash 'c hash) 3)
|
||
|
(remhash 'b hash)
|
||
|
hash)
|
||
|
#<HASH-TABLE :TEST EQL :COUNT 2 {100758CFB3}>
|
||
|
</code></pre>
|
||
|
<p>There's a few different ways of iterating over a Hash Table, depending on specifically what you're up to. If you're looking to make some destructive changes, or maybe just print pairs, there's <code>maphash</code>.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">let</span> ((<span class="hljs-name">hash</span> (<span class="hljs-name">make-hash-table</span>)))
|
||
|
(<span class="hljs-name">setf</span> (<span class="hljs-name">gethash</span> 'a hash) <span class="hljs-number">1</span>
|
||
|
(<span class="hljs-name">gethash</span> 'b hash) <span class="hljs-number">2</span>
|
||
|
(<span class="hljs-name">gethash</span> 'c hash) <span class="hljs-number">3</span>)
|
||
|
(<span class="hljs-name">maphash</span> (<span class="hljs-name">lambda</span> (<span class="hljs-name">k</span> v) (<span class="hljs-name">format</span> <span class="hljs-literal">t</span> <span class="hljs-string">"~a -> ~a~%"</span> k v)) hash))
|
||
|
A -> <span class="hljs-number">1</span>
|
||
|
B -> <span class="hljs-number">2</span>
|
||
|
C -> <span class="hljs-number">3</span>
|
||
|
NIL
|
||
|
</code></pre>
|
||
|
<p>Note that <code>maphash</code> doesn't collect results, so you couldn't convert a Hash Table to an <code>alist</code> by calling it with <code>cons</code>.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">let</span> ((<span class="hljs-name">hash</span> (<span class="hljs-name">make-hash-table</span>)))
|
||
|
(<span class="hljs-name">setf</span> (<span class="hljs-name">gethash</span> 'a hash) <span class="hljs-number">1</span>
|
||
|
(<span class="hljs-name">gethash</span> 'b hash) <span class="hljs-number">2</span>
|
||
|
(<span class="hljs-name">gethash</span> 'c hash) <span class="hljs-number">3</span>)
|
||
|
(<span class="hljs-name">maphash</span> #'cons hash))
|
||
|
NIL
|
||
|
</code></pre>
|
||
|
<p>If you wanted that, you'd either need to use some functions from <a href="https://llthw.common-lisp.dev/TODO%20link%20to%20alexandria%20chapter"><code>alexandria</code></a>, or a specific piece of <a href="https://llthw.common-lisp.dev/TODO%20link%20to%20the%20loop%20section%20(assuming%20there%20is%20one"><code>loop</code></a>)...</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">let</span> ((<span class="hljs-name">hash</span> (<span class="hljs-name">make-hash-table</span>)))
|
||
|
(<span class="hljs-name">setf</span> (<span class="hljs-name">gethash</span> 'a hash) <span class="hljs-number">1</span>
|
||
|
(<span class="hljs-name">gethash</span> 'b hash) <span class="hljs-number">2</span>
|
||
|
(<span class="hljs-name">gethash</span> 'c hash) <span class="hljs-number">3</span>)
|
||
|
(<span class="hljs-name">loop</span> for k being the hash-keys of hash
|
||
|
for v being the hash-values of hash
|
||
|
collect (<span class="hljs-name">cons</span> k v)))
|
||
|
((<span class="hljs-name">A</span> . <span class="hljs-number">1</span>) (<span class="hljs-name">B</span> . <span class="hljs-number">2</span>) (<span class="hljs-name">C</span> . <span class="hljs-number">3</span>))
|
||
|
</code></pre>
|
||
|
<p>... or you'd set up your own accumulator explicitly.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">let</span> ((<span class="hljs-name">hash</span> (<span class="hljs-name">make-hash-table</span>))
|
||
|
(<span class="hljs-name">acc</span> <span class="hljs-literal">nil</span>))
|
||
|
(<span class="hljs-name">setf</span> (<span class="hljs-name">gethash</span> 'a hash) <span class="hljs-number">1</span>
|
||
|
(<span class="hljs-name">gethash</span> 'b hash) <span class="hljs-number">2</span>
|
||
|
(<span class="hljs-name">gethash</span> 'c hash) <span class="hljs-number">3</span>)
|
||
|
(<span class="hljs-name">maphash</span> (<span class="hljs-name">lambda</span> (<span class="hljs-name">k</span> v) (<span class="hljs-name">push</span> (<span class="hljs-name">cons</span> k v) acc)) hash)
|
||
|
acc)
|
||
|
((<span class="hljs-name">C</span> . <span class="hljs-number">3</span>) (<span class="hljs-name">B</span> . <span class="hljs-number">2</span>) (<span class="hljs-name">A</span> . <span class="hljs-number">1</span>))
|
||
|
</code></pre>
|
||
|
<h3 id="exercise-1515">Exercise 1.5.15</h3>
|
||
|
<p><strong>Object Reference</strong></p>
|
||
|
<p>Speaking of Objects, there are two constructs in Common Lisp that give you some behaviors you might expect from them; <code>class</code>es and <code>struct</code>s. This exercise won't be a complete treatment, but will show you the basics.</p>
|
||
|
<pre><code class="lang-lisp">* (defclass foo ()
|
||
|
((a :initform 1)
|
||
|
(b :initform 2)
|
||
|
(c :initform 3)))
|
||
|
#<STANDARD-CLASS FOO>
|
||
|
|
||
|
* (make-instance 'foo)
|
||
|
#<FOO {10058567E3}>
|
||
|
|
||
|
* (slot-value (make-instance 'foo) 'a)
|
||
|
1
|
||
|
|
||
|
* (slot-value (make-instance 'foo) 'c)
|
||
|
3
|
||
|
</code></pre>
|
||
|
<p>Instead of using <code>slot-value</code>, it's possible to define reader and accessor functions for individual slots.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defclass</span> bar ()
|
||
|
((<span class="hljs-name">a</span> <span class="hljs-symbol">:initform</span> <span class="hljs-number">1</span> <span class="hljs-symbol">:reader</span> a)
|
||
|
(<span class="hljs-name">b</span> <span class="hljs-symbol">:initform</span> <span class="hljs-number">2</span> <span class="hljs-symbol">:accessor</span> b)
|
||
|
(<span class="hljs-name">c</span> <span class="hljs-symbol">:initform</span> <span class="hljs-number">3</span>)))
|
||
|
#<STANDARD-CLASS BAR>
|
||
|
|
||
|
* (<span class="hljs-name">a</span> (<span class="hljs-name">make-instance</span> 'bar))
|
||
|
<span class="hljs-number">1</span>
|
||
|
|
||
|
* (<span class="hljs-name">b</span> (<span class="hljs-name">make-instance</span> 'bar))
|
||
|
<span class="hljs-number">2</span>
|
||
|
</code></pre>
|
||
|
<p>A <code>reader</code> is basically just a getter function. You can't set its value directly.</p>
|
||
|
<pre><code class="lang-lisp">* (defparameter *instance* (make-instance 'bar))
|
||
|
*INSTANCE*
|
||
|
|
||
|
* *instance*
|
||
|
#<BAR {1005F806E3}>
|
||
|
|
||
|
* (a *instance*)
|
||
|
1
|
||
|
|
||
|
* (setf (a *instance*) 32)
|
||
|
Evaluation aborted on #<UNDEFINED-FUNCTION (SETF A) {1005DCB833}>.
|
||
|
</code></pre>
|
||
|
<p>An <code>accessor</code> on the other hand, is both a getter and a setter. So you can both read and assign through the interface it sets up.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">b</span> *instance*)
|
||
|
<span class="hljs-number">2</span>
|
||
|
|
||
|
* (<span class="hljs-name">setf</span> (<span class="hljs-name">b</span> *instance*) <span class="hljs-number">32</span>)
|
||
|
<span class="hljs-number">32</span>
|
||
|
|
||
|
* (<span class="hljs-name">b</span> *instance*)
|
||
|
<span class="hljs-number">32</span>
|
||
|
</code></pre>
|
||
|
<p>This isn't the same as setting public or private methods though. Even if you don't expose an accessor, it's possible to set a slots' value using the <code>slot-value</code> function.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">setf</span> (<span class="hljs-name">slot-value</span> *instance* 'a) <span class="hljs-number">16</span>)
|
||
|
<span class="hljs-number">16</span>
|
||
|
|
||
|
* (<span class="hljs-name">a</span> *instance*)
|
||
|
<span class="hljs-number">16</span>
|
||
|
</code></pre>
|
||
|
<p>Unlike the key--value constructs we've seen so far, there isn't an easy and portable (across Common Lisp implementations) way to iterate over keys and values. If you want that, you're stuck doing something a touch hacky. In real life, it would be <em>a bit</em> less hacky (see <a href="https://github.com/Inaimathi/cl-mop/blob/master/package.lisp" target="_blank">here</a> for what you'd really do), but we haven't covered packages yet.</p>
|
||
|
<pre><code class="lang-lisp">* (<span class="hljs-name">defun</span> class-slots (<span class="hljs-name">class</span>)
|
||
|
#+openmcl-native-threads (<span class="hljs-name">ccl</span><span class="hljs-symbol">:class-slots</span> class)
|
||
|
#+cmu (<span class="hljs-name">pcl</span><span class="hljs-symbol">:class-slots</span> class)
|
||
|
#+sbcl (<span class="hljs-name">sb-pcl</span><span class="hljs-symbol">:class-slots</span> class)
|
||
|
#+lispworks (<span class="hljs-name">hcl</span><span class="hljs-symbol">:class-slots</span> class)
|
||
|
#+allegro (<span class="hljs-name">mop</span><span class="hljs-symbol">:class-slots</span> class)
|
||
|
#+clisp (<span class="hljs-name">clos</span><span class="hljs-symbol">:class-slots</span> class))
|
||
|
CLASS-SLOTS
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> slot-definition-name (<span class="hljs-name">slot</span>)
|
||
|
#+openmcl-native-threads (<span class="hljs-name">ccl</span><span class="hljs-symbol">:slot-definition-name</span> slot)
|
||
|
#+cmu (<span class="hljs-name">pcl</span><span class="hljs-symbol">:slot-definition-name</span> slot)
|
||
|
#+sbcl (<span class="hljs-name">sb-pcl</span><span class="hljs-symbol">:slot-definition-name</span> slot)
|
||
|
#+lispworks (<span class="hljs-name">hcl</span><span class="hljs-symbol">:slot-definition-name</span> slot)
|
||
|
#+allegro (<span class="hljs-name">mop</span><span class="hljs-symbol">:slot-definition-name</span> slot)
|
||
|
#+clisp (<span class="hljs-name">clos</span><span class="hljs-symbol">:slot-definition-name</span> slot))
|
||
|
|
||
|
* (<span class="hljs-name">defun</span> map-slots (<span class="hljs-name">fn</span> instance)
|
||
|
(<span class="hljs-name">loop</span> for slot in (<span class="hljs-name">class-slots</span> (<span class="hljs-name">class-of</span> instance))
|
||
|
for slot-name = (<span class="hljs-name">slot-definition-name</span> slot)
|
||
|
collect (<span class="hljs-name">when</span> (<span class="hljs-name">slot-boundp</span> instance slot-name)
|
||
|
(<span class="hljs-name">funcall</span> fn slot-name (<span class="hljs-name">slot-value</span> instance slot-name)))))
|
||
|
MAP-SLOTS
|
||
|
|
||
|
* (<span class="hljs-name">map-slots</span> (<span class="hljs-name">lambda</span> (<span class="hljs-name">k</span> v) (<span class="hljs-name">list</span> k v)) *instance*)
|
||
|
((<span class="hljs-name">A</span> <span class="hljs-number">16</span>) (<span class="hljs-name">B</span> <span class="hljs-number">32</span>) (<span class="hljs-name">C</span> <span class="hljs-number">3</span>))
|
||
|
</code></pre>
|
||
|
<h3 id="exercise-1516">Exercise 1.5.16</h3>
|
||
|
<p><strong>Acyclic Graphs</strong></p>
|
||
|
<p>(TODO)</p>
|
||
|
|
||
|
|
||
|
</section>
|
||
|
|
||
|
</div>
|
||
|
<div class="search-results">
|
||
|
<div class="has-results">
|
||
|
|
||
|
<h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
|
||
|
<ul class="search-results-list"></ul>
|
||
|
|
||
|
</div>
|
||
|
<div class="no-results">
|
||
|
|
||
|
<h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
|
||
|
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
<a href="1-04-0-lists.html" class="navigation navigation-prev " aria-label="Previous page: Lists and List-Operations">
|
||
|
<i class="fa fa-angle-left"></i>
|
||
|
</a>
|
||
|
|
||
|
|
||
|
<a href="1-06-0-math.html" class="navigation navigation-next " aria-label="Next page: Numbers and Math">
|
||
|
<i class="fa fa-angle-right"></i>
|
||
|
</a>
|
||
|
|
||
|
|
||
|
|
||
|
</div>
|
||
|
|
||
|
<script>
|
||
|
var gitbook = gitbook || [];
|
||
|
gitbook.push(function() {
|
||
|
gitbook.page.hasChanged({"page":{"title":"Extra Credit: Look-up Lists and Trees","level":"3.1.5","depth":2,"next":{"title":"Numbers and Math","level":"3.1.6","depth":2,"path":"1-06-0-math.md","ref":"./1-06-0-math.md","articles":[{"title":"Integers","level":"3.1.6.1","depth":3,"path":"1-06-01-integers.md","ref":"./1-06-01-integers.md","articles":[]},{"title":"More Integers","level":"3.1.6.2","depth":3,"path":"1-06-02-more-integers.md","ref":"./1-06-02-more-integers.md","articles":[]},{"title":"Hexadecimal Integer Notation","level":"3.1.6.3","depth":3,"path":"1-06-03-hexadecimal-notation.md","ref":"./1-06-03-hexadecimal-notation.md","articles":[]},{"title":"Octal Integer Notation","level":"3.1.6.4","depth":3,"path":"1-06-04-octal-notation.md","ref":"./1-06-04-octal-notation.md","articles":[]},{"title":"Binary Integer Notation","level":"3.1.6.5","depth":3,"path":"1-06-05-binary-notation.md","ref":"./1-06-05-binary-notation.md","articles":[]},{"title":"Ratios and Rational Numbers","level":"3.1.6.6","depth":3,"path":"1-06-06-ratios.md","ref":"./1-06-06-ratios.md","articles":[]},{"title":"Floating-point Numbers","level":"3.1.6.7","depth":3,"path":"1-06-07-floating-point.md","ref":"./1-06-07-floating-point.md","articles":[]},{"title":"Numeric Constants","level":"3.1.6.8","depth":3,"path":"1-06-08-constants.md","ref":"./1-06-08-constants.md","articles":[]},{"title":"Complex Numbers","level":"3.1.6.9","depth":3,"path":"1-06-09-complex-numbers.md","ref":"./1-06-09-complex-numbers.md","articles":[]},{"title":"Arithmetic","level":"3.1.6.10","depth":3,"path":"1-06-10-arithmetic.md","ref":"./1-06-10-arithmetic.md","articles":[]},{"title":"More Arithmetic","level":"3.1.6.11","depth":3,"path":"1-06-11-more-arithmetic.md","ref":"./1-06-11-more-arithmetic.md","articles":[]},{"title":"Even More Arithmetic","level":"3.1.6.12","depth":3,"path":"1-06-12-even-more-arithmetic.md","ref":"./1-06-12-even-more-arithmetic.md","articles":[]},{"title":"Exponents","level":"3.1.6.13","depth":3,"path":"1-06-13-exponents.md","ref":"./1-06-13-exponents.md","articles":[]},{"title":"Logarithms","level":"3.1.6.14","depth":3,"path":"1-06-14-logarithms.md","ref":"./1-06-14-logarithms.md","articles":[]},{"title":"Trigonometry","level":"3.1.6.15","depth":3,"path":"1-06-15-trigonometry.md","ref":"./1-06-15-trigonometry.md","articles":[]},{"title":"Pseudo-Random Numbers","level":"3.1.6.16","depth":3,"path":"1-06-16-psuedorandom-numbers.md","ref":"./1-06-16-psuedorandom-numbers.md","articles":[]}]},"previous":{"title":"Lists and List-Operations","level":"3.1.4","depth":2,"path":"1-04-0-lists.md","ref":"./1-04-0-lists.md","articles":[]},"dir":"ltr"},"config":{"plugins":["hints","folding-chapters"],"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"hints":{"danger":"fa fa-exclamation-circle","info":"fa fa-info-circle","tip":"fa fa-mortar-board","working":"fa fa-wrench"},"folding-chapters":{},"highlight":{},"search":{},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"fontsettings":{"theme":"white","family":"sans","size":2},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"theme":"default","author":"\"the Phoeron\" Colin J.E. Lupton","pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"structure":{"langs":"LANGS.md","readme":"index.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"title":"Learn Lisp The Hard Way","gitbook":"*"},"file":{"path":"1-05-0-lookups-trees.md","mtime":"2022-08-22T22:47:49.767Z","type":"markdown"},"gitbook":{"version":"3.2.3","
|
||
|
});
|
||
|
</script>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<script src="gitbook/gitbook.js"></script>
|
||
|
<script src="gitbook/theme.js"></script>
|
||
|
|
||
|
|
||
|
<script src="gitbook/gitbook-plugin-folding-chapters/folding-chapters.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
<script src="gitbook/gitbook-plugin-search/search-engine.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
<script src="gitbook/gitbook-plugin-search/search.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
<script src="gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
<script src="gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
<script src="gitbook/gitbook-plugin-sharing/buttons.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
<script src="gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
</body>
|
||
|
</html>
|
||
|
|