O'Reilly logo

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Common Lisp Recipes: A Problem-Solution Approach

Book Description

Find solutions to problems and answers to questions you are likely to encounter when writing real-world applications in Common Lisp. This book covers areas as diverse as web programming, databases, graphical user interfaces, integration with other programming languages, multi-threading, and mobile devices as well as debugging techniques and optimization, to name just a few. Written by an author who has used Common Lisp in many successful commercial projects over more than a decade, Common Lisp Recipes is also the first Common Lisp book to tackle such advanced topics as environment access, logical pathnames, Gray streams, delivery of executables, pretty printing, setf expansions, or changing the syntax of Common Lisp.

The book is organized around specific problems or questions each followed by ready-to-use example solutions and clear explanations of the concepts involved, plus pointers to alternatives and more information. Each recipe can be read independently of the others and thus the book will earn a special place on your bookshelf as a reference work you always want to have within reach.

Common Lisp Recipes is aimed at programmers who are already familiar with Common Lisp to a certain extent but do not yet have the experience you typically only get from years of hacking in a specific computer language. It is written in a style that mixes hands-on no-frills pragmatism with precise information and prudent mentorship.

If you feel attracted to Common Lisp's mix of breathtaking features and down-to-earth utilitarianism, you'll also like this book.

Note: the author encourages readers to submit errata to http://weitz.de/cl-recipes/.

Table of Contents

  1. Cover
  2. Title
  3. Copyright
  4. Dedication
  5. Table of Contents
  6. About the Author
  7. About the Technical Reviewer
  8. Preface
    1. Who This Book Is For
    2. Who This Book Is (Probably) Not For
    3. How to Read This Book
    4. What’s In and What Not
    5. The HyperSpec
    6. Which Implementation
    7. Source Code
    8. The Index
    9. Typographical Conventions
    10. Acknowledgements
  9. 1. Symbols and Packages
    1. 1-1. Understanding the Role of Packages and the Symbol Nomenclature
    2. 1-2. Making Unique Symbols
    3. 1-3. Making Symbols Inaccessible
      1. How Can We Fix This?
    4. 1-4. Avoiding Name Conflicts
      1. When Name Conflicts Do Not Occur
    5. 1-5. Using Symbols As Stand-Ins for Arbitrary Forms
    6. 1-6. Searching for Symbols by Name
    7. 1-7. Iterating Through All Symbols of a Package
      1. What To Do If You Don’t Like LOOP
    8. 1-8. Understanding COMMON LISP ’s Case (In)Sensitivity
      1. Style Hint: Don’t Use CamelCase!
    9. 1-9. Using Symbols As String Substitutes
      1. So, What Should You Use?
    10. 1-10. “Overloading” of Standard COMMON LISP Operators
  10. 2. Conses, Lists, and Trees
    1. 2-1. Understanding Conses
      1. List Access
      2. Testing Whether Something Is a Cons or a List
    2. 2-2. Creating Lists
      1. Converting Vectors to Lists
    3. 2-3. Transposing a Matrix
    4. 2-4. Using List Interpolation
    5. 2-5. Adding Objects to the End of a List
      1. The Tail Wagging the List
    6. 2-6. “Splicing” into a List
    7. 2-7. Detecting Shared Structure in Lists
      1. Isolating the Non-Shared Part
    8. 2-8. Working with Trees
      1. More Complicated Trees
      2. COMMON LISP ’s Standard Tree Functions
    9. 2-9. Working with Stacks
    10. 2-10. Implementing a Queue
    11. 2-11. Destructuring and Pattern Matching
  11. 3. Strings and Characters
    1. 3-1. Getting the ASCII Code of a Character
      1. The Other Way Around
      2. The Limit
    2. 3-2. Naming Characters
    3. 3-3. Using Different Character Encodings
    4. 3-4. Comparing Strings or Characters
      1. Internationalization
    5. 3-5. Escaping Characters in String Literals and Variable Interpolation
      1. Is It Still a Literal?
    6. 3-6. Controlling Case
      1. What About Unicode?
    7. 3-7. Accessing or Modifying a Substring
    8. 3-8. Finding a Character or a SubstringWithin a String
    9. 3-9. Trimming Strings
    10. 3-10. Processing a String One Character at a Time
    11. 3-11. Joining Strings
    12. 3-12. Reading CSV Data
  12. 4. Numbers and Math
    1. 4-1. Using Arbitrarily Large Integers
    2. 4-2. Understanding Fixnums
    3. 4-3. Performing Modular Arithmetic
      1. Efficiency Considerations
    4. 4-4. Switching Bases
    5. 4-5. Performing Exact Arithmetic with Rational Numbers
      1. Various Ways of Converting Numbers to Integers
      2. How Not to Use FLOOR and Friends
      3. Converting Floating-Point Numbers to Rationals and Vice Versa
      4. Mixing Rationals and Floats
    6. 4-6. Controlling the Default Float Format
    7. 4-7. Employing Arbitrary Precision Floats
    8. 4-8. Working with Complex Numbers
    9. 4-9. Parsing Numbers
    10. 4-10. Testing Whether Two Numbers Are Equal
      1. Don’t Ever Use EQ with Numbers!
    11. 4-11. Computing Angles Correctly
    12. 4-12. Calculating Exact Square Roots
  13. 5. Arrays and Vectors
    1. 5-1. Working with Multiple Dimensions
    2. 5-2. Understanding Vectors and Simple Arrays
    3. 5-3. Obtaining the Size of an Array
    4. 5-4. Providing Initial Contents
      1. A Warning About Identical Objects
    5. 5-5. Treating Arrays As Vectors
    6. 5-6. Making the Length of Vectors Flexible
    7. 5-7. Adjusting Arrays
    8. 5-8. Using an Array As a “Window” into Another Array
    9. 5-9. Restricting the Element Type of an Array
      1. Upgrading Element Types
    10. 5-10. Copying an Array
      1. A Warning About Object Identity
  14. 6. Hash Tables, Maps, and Sets
    1. 6-1. Understanding the Basics of Hash Tables
      1. Why Does GETHASH Return Two Values?
      2. How Many Entries Does the Hash Table Have?
    2. 6-2. Providing Default Values For Hash Table Lookups
    3. 6-3. Removing Hash Table Entries
    4. 6-4. Iterating Through a Hash Table
      1. Don’t Rely on Any Order!
      2. Don’t Modify While You’re Iterating!
      3. Can’t This Be More Concise, Please?
    5. 6-5. Understanding Hash Table Tests and Defining Your Own
      1. What Is SXHASH For?
    6. 6-6. Controlling Hash Table Growth
    7. 6-7. Getting Rid of Hash Table Entries Automatically
    8. 6-8. Representing Maps As Association Lists
      1. Combining Lookup and Manipulation
      2. Why Would Anybody Prefer Alists over Hash Tables?
    9. 6-9. Representing Maps As Property Lists
      1. When to Prefer Plists over Alists
      2. The Plist of a Symbol
    10. 6-10. Working with Sets
      1. Representing Sets As Hash Tables
      2. Representing Sets As Bit Patterns
  15. 7. Sequences and Iteration
    1. 7-1. Filtering a Sequence
    2. 7-2. Searching a Sequence
    3. 7-3. Sorting and Merging Sequences
    4. 7-4. Mixing Different Sequence Types
    5. 7-5. Re-Using a Part of a Sequence
    6. 7-6. Repeating Some Values Cyclically
      1. Alternatives
    7. 7-7. Counting Down
    8. 7-8. Iterating over “Chunks” of a List
    9. 7-9. Closing over Iteration Variables
    10. 7-10. “Extending” Short Sequences in Iterations
    11. 7-11. Breaking out of LOOP
    12. 7-12. Making Sense of the MAP... Zoo
      1. The Sequence Variants
    13. 7-13. Defining Your Own Sequence Types
    14. 7-14. Iterating with ITERATE
    15. 7-15. Iterating with SERIES
      1. What the Example Does
  16. 8. The Lisp Reader
    1. 8-1. Employing the Lisp Reader for Your Own Code
      1. Why READ Is Potentially Dangerous
      2. What READ Doesn’t Do
      3. The Optional Arguments to READ
      4. Go Wild!
    2. 8-2. Troubleshooting Literal Object Notation
      1. This Also Applies to Strings!
    3. 8-3. Evaluating Forms at Read Time
      1. What to Look Out For
      2. Alternatives
    4. 8-4. Embedding Literal Arrays into Your Code
      1. The Usual Warning
    5. 8-5. Understanding the DifferentWays to Refer to a Function
    6. 8-6. Repeating Something You Already Typed
      1. They Don’t Only Look Identical, They Are Identical!
    7. 8-7. Safely Experimenting with Readtables
      1. Temporarily Switching to Standard IO Syntax
    8. 8-8. Changing the Syntax Type of a Character
      1. The Six Syntax Types
      2. How to Actually Change the Syntax Type
      3. Some Things Never Change
    9. 8-9. Creating Your Own Reader Macros
      1. What Reader Macro Functions Do
    10. 8-10. Working with Dispatching Macro Characters
    11. 8-11. Preserving Whitespace
  17. 9. Printing
    1. 9-1. Using the Printing Primitives
      1. Printing Objects So That They Can Be Read Back in Again
      2. Shortcuts
    2. 9-2. Printing to and into Strings
    3. 9-3. Printing NIL As a List
    4. 9-4. Extending FORMAT Control Strings Over More Than One Line
    5. 9-5. Using Functions As FORMAT Controls
    6. 9-6. Creating Your Own FORMAT Directives
    7. 9-7. Recursive Processing of FORMAT Controls
    8. 9-8. Controlling How Your Own Objects Are Printed
    9. 9-9. Controlling the Pretty Printer
    10. 9-10. Printing Long Lists
    11. 9-11. Pretty-Printing Compound Objects
      1. Using the Pretty Printer from FORMAT
    12. 9-12. Modifying the Pretty Printer
  18. 10. Evaluation, Compilation, Control Flow
    1. 10-1. Comparing Arbitrary Lisp Objects
      1. Comparing State
      2. Constants
    2. 10-2. Using Constant Variables as Keys in CASE Macros
    3. 10-3. Using Arbitrary Variable Names for Keyword Parameters
      1. Keyword Names Don’t Have to Be Keywords
      2. Keyword Dames Don’t Have to Be Constant
    4. 10-4. Creating “Static Local Variables,” Like in C
    5. 10-5. “Preponing” the Computation of Values
    6. 10-6. Modifying the Behavior of Functions You Don’t Have the Source Of
    7. 10-7. Swapping the Values of Variables (or Places)
    8. 10-8. Creating Your Own Update Forms for “Places”
      1. Using DEFSETF
      2. Using DEFINE-SETF-EXPANDER
      3. So, Which One Do I Use?
      4. Using DEFINE-MODIFY-MACRO
      5. Multiple-Valued Places
    9. 10-9. Working with Environments
    10. 10-10. Commenting Out Parts of Your Code
      1. Some Notes About ; and #|
      2. How ; , #| , and Others Are Implemented
  19. 11. Concurrency
    1. 11-1. Managing Lisp Processes
      1. Escape Hatches
      2. Threads Are Expensive
    2. 11-2. Accessing Shared Resources Concurrently
      1. Locks
      2. Atomic Operations
      3. More Problems
    3. 11-3. Using Special Variables in Concurrent Programs
      1. Per-Thread Initial Bindings
      2. Variables That Are Always Global
    4. 11-4. Communicating with Other Threads
      1. Alternatives
    5. 11-5. Parallelizing AlgorithmsWithout Threads and Locks
      1. What the Example Does
      2. Fine-Tuning
      3. Ptrees
      4. Alternatives
    6. 11-6. Determining the Number of Cores
  20. 12. Error Handling and Avoidance
    1. 12-1. Checking Types at Run Time
      1. Alternatives
    2. 12-2. Adding Assertions to Your Code
      1. Disabling Assertions in “Production Code”
    3. 12-3. Defining Your Own Conditions
      1. How Conditions Are Printed
    4. 12-4. Signaling a Condition
      1. Condition Designators
    5. 12-5. Handling Conditions
      1. Ignoring Errors
    6. 12-6. Providing and Using Restarts
      1. Visible Restarts
      2. Predefined Restarts
    7. 12-7. Getting Rid of Warning Messages
    8. 12-8. Protecting Code from Non-Local Exits
      1. “ WITH- ” Macros
  21. 13. Objects, Classes, Types
    1. 13-1. Defining Types
      1. Compound Type Specifiers
      2. Derived Types
    2. 13-2. Using Classes As Types
    3. 13-3. Writing Methods for Built-In Classes
    4. 13-4. Providing Constructors for Your Classes
    5. 13-5. Marking Slots As “Private”
    6. 13-6. Changing the Argument Precedence Order
    7. 13-7. Automatically Initializing Slots on First Usage
    8. 13-8. Changing and Redefining Classes on the Fly
      1. Objects Changing Their Class
      2. Redefining Classes
    9. 13-9. Making Your Objects Externalizable
    10. 13-10. Using and Defining Non-Standard Method Combinations
      1. Rolling Your Own
      2. Arbitrarily Complex Method Combinations
    11. 13-11. Extending and Modifying CLOS
      1. What the example does
  22. 14. I/O: Streams and Files
    1. 14-1. Redirecting Streams
      1. Other Ways to Do It
      2. Synonym Streams
    2. 14-2. Flushing an Output Stream
    3. 14-3. Determining the Size of a File
    4. 14-4. Reading a Whole File at Once
      1. Alternatives
    5. 14-5. Sending Data to Two Streams in Parallel
      1. Synonym Streams
    6. 14-6. Sending Data to “ /dev/null ”
    7. 14-7. Pretending a String Is a Stream
      1. More Details
    8. 14-8. Concatenating Streams
    9. 14-9. Processing Text Files Line by Line
      1. What Happens at the End of a Line?
      2. What Happens at the End of the File?
    10. 14-10. Working with Binary Data
      1. Reading or Writing Several Bytes at Once
      2. You Might Get Bigger Chunks Than You Asked For
    11. 14-11. Reading “Foreign” Binary Data
      1. Floating-Point Values
    12. 14-12. Using Random Access I/O
      1. Different Characters May Have Different Lengths
    13. 14-13. Serializing Lisp Objects
      1. Shared Structure
      2. Is It Readable?
      3. Can This Be Done Faster, Please?
      4. What About JSON or Other Formats?
    14. 14-14. Customizing Stream Behavior
  23. 15. Pathnames, Files, Directories
    1. 15-1. Getting and Setting the Current Directory
      1. Shortcuts and Deviations
    2. 15-2. Testing Whether a File Exists
      1. What About Directories?
    3. 15-3. Creating a Directory
      1. Implementation-Specific Alternatives
      2. What Might Go Wrong
    4. 15-4. Finding Files Matching a Pattern
    5. 15-5. Splitting a Filename into its Component Parts
    6. 15-6. Renaming a File
      1. Implementation-Specific Alternatives
      2. Don’t Expect “Move” Behavior!
    7. 15-7. Deleting a File
      1. What Does “Success” Mean Anyway?
    8. 15-8. Deleting a Directory
    9. 15-9. Copying a File
    10. 15-10. Processing the Contents of a Directory Recursively
      1. The CL-FAD Library
    11. 15-11. Getting the Pathname a Stream Is AssociatedWith
    12. 15-12. Dealing with Symbolic Links
      1. What If I Want the Symlinks?
    13. 15-13. Navigating a Directory Tree
    14. 15-14. Figuring Out (Source) File Locations Programmatically
    15. 15-15. Understanding Logical Pathnames
      1. What Exactly Are Logical Pathnames?
      2. So, Maybe Logical Pathnames Aren’t Totally Useless.
  24. 16. Developing and Debugging
    1. 16-1. Embracing Lisp’s Image-Based Development Style
      1. The Role of the Source Code
    2. 16-2. Deciding Which IDE to Use
      1. A Brief History of Emacs (As Seen from Lisp)
      2. Alternatives (?)
    3. 16-3. Debugging with the Debugger
      1. Entering the Debugger Intentionally
      2. Without SLIME
      3. Logging Backtraces
    4. 16-4. Tracing Functions
      1. Graphical Tracing
    5. 16-5. Stepping Through Your Code
    6. 16-6. Acquiring Information About Functions, Macros, and Variables
      1. Accessing the HyperSpec
      2. Cross-Reference Information
    7. 16-7. Inspecting and Modifying (Compound) Objects
      1. The SLIME Inspector
    8. 16-8. Browsing Your Lisp Image
      1. Alternatives
    9. 16-9. “Undoing” Definitions
    10. 16-10. Distinguishing Your IDE’s Streams
    11. 16-11. Utilizing the REPL’s Memory
      1. IDE History Features
    12. 16-12. Recording Your Work
  25. 17. Optimization
    1. 17-1. Understanding the Importance of the Right Algorithms
    2. 17-2. Deciding If and Where to Optimize
      1. Instrumentation
      2. Statistical Profiling
      3. Some Things Cannot Be Profiled
      4. Where to Go From Here
      5. A Warning About Empirical Data
      6. What Does TIME Do?
      7. CPUs Can Deceive You
    3. 17-3. Asking the Compiler to Optimize
      1. Implementation-Defined Optimize Qualities
      2. Can I Have This Global, Please?
      3. Compilers Aren’tWizards
    4. 17-4. Obtaining Optimization Hints from the Compiler
    5. 17-5. Helping the Compiler by Providing Type Information
      1. Generic Operations
      2. Boxing
      3. How to Declare Types
      4. The Scope of Type Declarations
      5. Declaring the Return Type of Forms
      6. Type Inference
      7. Pitfalls
    6. 17-6. Reducing “Consing”
      1. “Consing” and the Heap
      2. Reusing Data Structures
      3. Destructive Functions
      4. “Hidden” Consing
      5. “Tuning” the Garbage Collector
    7. 17-7. Using the Stack Instead of the Heap
      1. Multiple Values
    8. 17-8. Optimizing Recursive Functions
    9. 17-9. Helping the Compiler with Alternative Implementation Strategies .
    10. 17-10. Avoiding Repeated Computations
    11. 17-11. Avoiding Function Calls
      1. Alternatives That Aren’t Really Alternatives
      2. The NOTINLINE Declaration and Compiler Macros
    12. 17-12. Utilizing the Disassembler
    13. 17-13. Switching to Machine Code
      1. Inline Assembly Code
    14. 17-14. Optimizing Array Access
    15. 17-15. Comparing Different Implementations
  26. 18. Libraries
    1. 18-1. Organizing Your Code
      1. Components
      2. Dependencies
      3. How Does ASDF Find System Definitions?
      4. Additional Information
      5. What About the Names?
      6. Advanced Usage of ASDF
    2. 18-2. Employing Open Source Libraries
      1. Installing QUICKLISP
      2. Using QUICKLISP for Your Own Code
    3. 18-3. Creating a Project’s Skeleton Automatically
    4. 18-4. Avoiding Wheel-Reinvention
    5. 18-5. Using Libraries to Write Portable Code
    6. 18-6. Utilizing Regular Expressions
      1. Regex Syntax
      2. Scanners
      3. Convenience Features
      4. Modifying and Dissecting Strings
      5. More Information
    7. 18-7. Obtaining Data via HTTP
      1. Parsing HTML
    8. 18-8. Creating DynamicWeb Sites with Lisp
      1. Generating HTML
      2. Web Frameworks
  27. 19. Interfacing with Other Languages
    1. 19-1. Calling C Functions from Lisp
      1. How the FFI Finds and Loads Shared Libraries
      2. How the FFI Calls C Functions
      3. How the FFI Converts Between C and Lisp Types
      4. The “ stdcall Problem”
    2. 19-2. Working with C Pointers
      1. Typed Pointers
    3. 19-3. Accessing and Generating C Arrays
      1. Giving C Access to Lisp Arrays
    4. 19-4. Handling C Structs and Unions
      1. Passing Structs by Value
    5. 19-5. Converting Between Lisp and C Strings
    6. 19-6. Calling Lisp Functions from C
    7. 19-7. Generating FFI Code Automatically
    8. 19-8. Embedding C in COMMON LISP
    9. 19-9. Calling C++ from Lisp
      1. Automating the Process
      2. ECL and C LASP
    10. 19-10. Using JAVA from Lisp
      1. Alternatives
    11. 19-11. Reading andWriting JSON
    12. 19-12. Reading andWriting XML
    13. 19-13. Using PROLOG from COMMON LISP
  28. 20. Graphical User Interfaces
    1. 20-1. Using aWeb Browser as the GUI for Your Lisp Program
      1. What the Example Does
    2. 20-2. Building Applications with the “ Lisp Toolkit ”
      1. What the Example Does
    3. 20-3. Creating COMMON LISP GUIs Through JAVA
      1. What the Example Does
      2. A Better Example
    4. 20-4. Using CAPI to Build Graphical User Interfaces
      1. What the Example Does
    5. 20-5. Using Lisp on Mobile Devices
      1. Alternatives
  29. 21. Persistence
    1. 21-1. Serializing Your Data
    2. 21-2. Accessing Relational Databases
    3. 21-3. Keeping Your Database in RAM
    4. 21-4. Using a Lisp Object Database
  30. 22. TheWorld Outside
    1. 22-1. Accessing Environment Variables
      1. The Windows Registry and Application-Specific Settings
    2. 22-2. Accessing the Command-Line Arguments
    3. 22-3. Querying Your Lisp for Information About Its Environment
    4. 22-4. Delivering Stand-Alone Executables
      1. Delivering Programs with the Commercial Lisps
    5. 22-5. Customizing Your Lisp
      1. Saving an Image
    6. 22-6. Running External Programs
    7. 22-7. Embedding Lisp
      1. Creating Shared Libraries with LISP WORKS
      2. Embedding ABCL in a JAVA Program
    8. 22-8. Measuring Time
    9. 22-9. Working with Dates and Times
      1. The LOCAL - TIME Library
    10. 22-10. Working with the Garbage Collector
      1. Finalizers
  31. Index