### Install Serapeum via Quicklisp Source: https://context7.com/ruricolist/serapeum/llms.txt Instructions for installing the Serapeum library and its modules using Quicklisp. It also shows how to use Serapeum within a package definition, either directly or with local nicknames. ```lisp ;; Install via Quicklisp (ql:quickload "serapeum") ;; Load specific modules (ql:quickload "serapeum/types") (ql:quickload "serapeum/control-flow") ;; Use in a package (defpackage :my-package (:use #:cl #:alexandria #:serapeum)) ;; Or use the bundle with local nicknames (defpackage :my-package (:local-nicknames (:util :serapeum/bundle))) ``` -------------------------------- ### Install Serapeum using Quicklisp Source: https://github.com/ruricolist/serapeum/blob/master/README.md This code snippet demonstrates how to install the Serapeum library using the Quicklisp package manager. It assumes Quicklisp is already set up in your Common Lisp environment. ```common-lisp (ql:quickload "serapeum") ``` -------------------------------- ### Example Macro (example) - Common Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md The `example` macro functions identically to the `comment` macro. It ignores its body, providing a way to embed non-executable examples or comments within code, which can be especially useful during macro expansion. ```common-lisp (example &body body) ``` -------------------------------- ### Using Serapeum with Alexandria and local nicknames Source: https://github.com/ruricolist/serapeum/blob/master/README.md This example illustrates how to use Serapeum in conjunction with Alexandria, another Common Lisp utility library. It shows the use of package definitions with `:use` clauses and the alternative approach using package-local nicknames for brevity. ```common-lisp (defpackage ... (:use #:cl #:alexandria #:serapeum)) ``` ```common-lisp (defpackage ... (:local-nicknames (:util :serapeum/bundle))) ``` -------------------------------- ### Sequence Prefix and Suffix Handling Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Functions to ensure a sequence starts with a given prefix or ends with a given suffix. If the sequence already meets the criteria, it is returned unchanged. ```APIDOC ## ensure-prefix prefix seq &key test ### Description Return a sequence like SEQ, but starting with PREFIX. If SEQ already starts with PREFIX, return SEQ. ### Method (ensure-prefix prefix seq &key test) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```lisp (ensure-prefix "abc" "abcdef") ;; => "abcdef" (ensure-prefix "abc" "xyzabc") ;; => "xyzabc" ``` ### Response #### Success Response (200) Returns the modified or original sequence. #### Response Example ```lisp "abcdef" ``` ## ensure-suffix seq suffix &key test ### Description Return a sequence like SEQ, but ending with SUFFIX. If SEQ already ends with SUFFIX, return SEQ. ### Method (ensure-suffix seq suffix &key test) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```lisp (ensure-suffix "def" "abcdef") ;; => "abcdef" (ensure-suffix "def" "abcxyz") ;; => "abcxyzdef" ``` ### Response #### Success Response (200) Returns the modified or original sequence. #### Response Example ```lisp "abcdef" ``` ``` -------------------------------- ### Queue Operations (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Provides a set of functions for managing queues, inspired by Norvig's implementation but wrapped in objects for better printer output and featuring an Arc-inspired API. Operations include testing for a queue (`queuep`), creating a queue (`queue`), clearing a queue (`clear-queue`), getting queue length (`qlen`), converting to a list (`qlist`), enqueuing (`enq`), dequeuing (`deq`), adding to the front (`undeq`), checking for emptiness (`queue-empty-p`), accessing the front (`front`) and back (`qback`) elements, concatenating lists (`qconc`, `qappend`), prepending lists (`qprepend`, `qpreconc`), and copying a queue (`copy-queue`). ```lisp (queuep g) (queue &rest initial-contents) (clear-queue queue) (qlen queue) (qlist queue) (enq item queue) (deq queue) (undeq item queue) (queue-empty-p queue) (front queue) (qback queue) (qconc queue list) (qappend queue list) (qprepend list queue) (qpreconc list queue) (copy-queue queue) ``` -------------------------------- ### Ensure Prefix for Sequences (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Ensures a sequence starts with a given prefix. If the sequence already begins with the prefix, it is returned as is. Otherwise, a new sequence is constructed with the prefix prepended. ```lisp (ensure-prefix prefix seq &key test) ``` -------------------------------- ### File Operations Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Functions for reading from and writing to files, comparing files, getting file sizes, and handling executable file paths. ```APIDOC ## write-stream-into-file stream pathname ### Description Read STREAM and write the contents into PATHNAME. STREAM will be closed afterwards, so wrap it with `make-concatenated-stream` if you want it left open. ### Method (write-stream-into-file stream pathname &key if-exists if-does-not-exist) ### Endpoint N/A (Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ``` ```APIDOC ## write-file-into-stream pathname output ### Description Write the contents of FILE into STREAM. ### Method (write-file-into-stream pathname output &key if-does-not-exist external-format) ### Endpoint N/A (Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ``` ```APIDOC ## file= file1 file2 ### Description Compare FILE1 and FILE2 octet by octet, (possibly) using buffers of BUFFER-SIZE. ### Method (file= file1 file2 &key buffer-size) ### Endpoint N/A (Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ``` ```APIDOC ## file-size file ### Description The size of FILE, in units of ELEMENT-TYPE (defaults to bytes). The size is computed by opening the file and getting the length of the resulting stream. If all you want is to read the file's size in octets from its metadata, consider `trivial-file-size:file-size-in-octets` instead. ### Method (file-size file &key element-type) ### Endpoint N/A (Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ``` ```APIDOC ## exe p ### Description If P, a pathname designator, has no extension, then, on Windows only, add an extension of `.exe`. ### Method (exe p) ### Endpoint N/A (Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ``` ```APIDOC ## resolve-executable p ### Description Look for an executable using the PATH environment variable. P is a pathname designator. On Windows only, if P does not have an extension, it assumed to end in `.exe`. Note that this function does not check the current directory (even on Windows) and it does not care if P is already an absolute pathname: it only cares about its name and type. ### Method (resolve-executable p) ### Endpoint N/A (Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ``` ```APIDOC ## format-file-size-human-readable stream file-size ### Description Write FILE-SIZE, a file size in bytes, to STREAM, in human-readable form. STREAM is interpreted as by `format`. If FLAVOR is nil, kilobytes are 1024 bytes and SI prefixes are used. If FLAVOR is `:si`, kilobytes are 1000 bytes and SI prefixes are used. If FLAVOR is `:iec`, kilobytes are 1024 bytes and IEC prefixes (Ki, Mi, etc.) are used. If SPACE is non-nil, include a space between the number and the prefix. (Defaults to T if FLAVOR is `:si`.) SUFFIX is the suffix to use; defaults to B if FLAVOR is `:iec`, otherwise empty. ### Method (format-file-size-human-readable stream file-size &key flavor space suffix) ### Endpoint N/A (Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ``` ```APIDOC ## file-size-human-readable file ### Description Format the size of FILE (in octets) using `format-file-size-human-readable`. The size of file is found by `trivial-file-size:file-size-in-octets`. Inspired by the function of the same name in Emacs. ### Method (file-size-human-readable file &key flavor space suffix stream) ### Endpoint N/A (Function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ``` -------------------------------- ### Split String into Lines with EOL Characters Kept (Python Equivalent) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md This example demonstrates splitting a string into lines while preserving the EOL characters, similar to Python's `str.splitlines()` behavior. It uses a specific EOL style and the `keep-eols` argument to retain the delimiter information within the resulting lines. ```common-lisp (serapeum:lines string :eol-style :lf :keep-eols t) ``` -------------------------------- ### Get Fundamental Array (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Recursively retrieves the fundamental array that a given array is displaced to. It returns the fundamental array along with the start and end positions within it. This function is borrowed from Erik Naggum. ```common-lisp (undisplace-array array) ``` -------------------------------- ### Create Instance with Shorthand (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md A shorthand for `make-instance` in CLOS. Offers enhanced compile-time argument checking and declares return types, potentially enabling more compiler warnings. ```lisp (make class &rest initargs &key &allow-other-keys) Shorthand for `make-instance`. Unlike `make-instance`, this is not a generic function, so it can do more compile-time argument checking. Also unlike `make-instance`, `make` is defined to always return a single value. It also declares its return type (as `standard-object`, or also `structure-object` if the implementation allows `make-instance` on structures). This may allow the compiler to warn you if you (e.g.) try to treat the return value as a list or number. After Eulisp. [View source](clos.lisp#L29) ``` -------------------------------- ### Get File Size in Common Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Retrieves the size of a file, defaulting to bytes. It computes the size by opening the file and getting the stream length. For metadata-based size, consider `trivial-file-size:file-size-in-octets`. ```common-lisp (file-size file &key element-type) ``` -------------------------------- ### Load a specific Serapeum module Source: https://github.com/ruricolist/serapeum/blob/master/README.md This code snippet shows how to load individual modules from the Serapeum library using Quicklisp. This allows for incremental adoption and reduces the overall load time if only specific functionalities are needed. ```common-lisp (ql:quickload "serapeum/types") ``` -------------------------------- ### Block Compilation with block-compile Source: https://github.com/ruricolist/serapeum/blob/master/README.md Illustrates using the `block-compile` macro for block compilation, ensuring that calls to entry points are compiled locally. This macro expands to a `labels` form with an `defalias` for the entry point. ```common-lisp (block-compile (:entry-points (entry-point)) (defun aux-fn-1 ...) (defun aux-fn-2 ...) (defun entry-point ...)) ``` ```common-lisp (labels ((aux-fn-2 ...) (aux-fn-1 ...) (entry-point ...)) (defalias entry-point #'entry-point)) ``` -------------------------------- ### Get Class Name of Object (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Retrieves the name of the class to which an object belongs. ```lisp (class-name-of x) The class name of the class of X. [View source](clos.lisp#L60) ``` -------------------------------- ### Block Compilation with `local*` and `block-compile` Macros Source: https://github.com/ruricolist/serapeum/blob/master/README.md Demonstrates how to use `local*` and `block-compile` macros for optimizing function definitions. `local*` is similar to `local` but preserves the last form, useful for block compilation in Lisps lacking native syntax. `block-compile` offers further optimization by ensuring entry point calls are compiled locally. ```common-lisp (progn (defun aux-fn-1 ...) (defun aux-fn-2 ...) (defun entry-point ...)) ``` ```common-lisp (local* (defun aux-fn-1 ...) (defun aux-fn-2 ...) (defun entry-point ...)) ``` ```common-lisp (labels ((aux-fn-2 ...) (aux-fn-1 ...)) (defun entry-point ...)) ``` ```common-lisp (block-compile (:entry-points (entry-point)) (defun aux-fn-1 ...) (defun aux-fn-2 ...) (defun entry-point ...)) ``` ```common-lisp (labels ((aux-fn-2 ...) (aux-fn-1 ...) (entry-point ...)) (defalias entry-point #'entry-point)) ``` -------------------------------- ### Get Class Name Safely (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Retrieves the class name of an object. If the object is a class, it returns the name of that class. ```lisp (class-name-safe x) The class name of the class of X. If X is a class, the name of the class itself. [View source](clos.lisp#L65) ``` -------------------------------- ### Get Current Unix Time (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Retrieves the current time as a count of seconds elapsed since the Unix epoch. ```lisp (get-unix-time) The current time as a count of seconds from the Unix epoch. [View source](time.lisp#L26) ``` -------------------------------- ### Concise Hash Table Constructor (Lisp) Source: https://context7.com/ruricolist/serapeum/llms.txt Provides a concise syntax for creating hash tables. It supports specifying the test function as the first argument for non-standard hash tables and integrates with pattern matching libraries. ```lisp ;; Create an equal hash table (dict :a 1 :b 2 :c 3) ;; => # (gethash :b (dict :a 1 :b 2 :c 3)) ;; => 2, T ;; Specify test as first arg (if odd number of args) (dict 'eq :a 1 :b 2) ; eq hash table ;; Use with Trivia pattern matching (match (dict :x 1 :y 2) ((dict :x x :y y) (+ x y))) ;; => 3 ``` -------------------------------- ### Memoized Fibonacci Function Expansion (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/README.md Illustrates the expansion of the `defmemo` macro when used at the top level with a `fibonacci` function. It shows how a `let` binding is created for the memoization table and `defun` is used for the function definition. ```common-lisp ;; This source form (defmemo fibonacci (n) (if (<= n 1) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) ;; Expands into... (let ((memo-table (make-hash-table :test 'equal))) (defun fibonacci (&rest args) (multiple-value-bind (result result?) (gethash args memo-table) (if result? result (setf (gethash args memo-table) (apply (lambda (n) (if (<= n 1) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) args)))))) ``` -------------------------------- ### Get Monitor Lock for an Object (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Returns a unique lock object associated with the provided object, intended for synchronization purposes. ```Common Lisp (monitor object) ``` -------------------------------- ### Top-Level Expansion of defmemo (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/README.md Illustrates how the `defmemo` macro expands when used at the top level. It shows the creation of a hash table and a `defun` form that utilizes it for memoization. ```common-lisp ;; This source form (defmemo fibonacci (n) (if (<= n 1) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) ;; Expands into... (let ((memo-table (make-hash-table :test 'equal))) (defun fibonacci (&rest args) (multiple-value-bind (result result?) (gethash args memo-table) (if result? result (setf (gethash args memo-table) (apply (lambda (n) (if (<= n 1) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) args)))))) ``` -------------------------------- ### Local Memoized Fibonacci Function Expansion (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/README.md Demonstrates the expansion of the `defmemo` macro within a `local` form. This shows how `labels` is used for the function definition and how the memoization table is managed within the local scope. ```common-lisp (local (defmemo fibonacci (n) (if (<= n 1) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) (fibonacci 100)) ;; Expands into this very different code (simplified for readability): (let (fn) (labels ((fibonacci (&rest args) (apply fn args))) (let ((memo-table (make-hash-table :test 'equal))) (setf fn (named-lambda fibonacci (&rest args) (multiple-value-bind (result result?) (gethash args memo-table) (if result? result (setf (gethash args memo-table) (apply (lambda (n) (if (<= n 1) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) args))))))) (fibonacci 100)))) ``` -------------------------------- ### Drop Prefix from Sequence (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Removes a specified prefix from a sequence if the sequence starts with that prefix. The `test` argument allows for custom equality checks. ```lisp (drop-prefix prefix seq &key test) ``` -------------------------------- ### Splice Sequence (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Removes a part of a sequence between START and END and replaces it with NEW contents. The original sequence is not modified. If NEW is omitted, elements are removed. ```lisp (splice-seq '(1 2 3 4 5) :new '(:a :b :c) :start 1 :end 1) => (1 :A :B :C 2 3 4 5) (splice-seq '(1 2 3 4 5) :new '(:a :b :c) :start 1 :end 4) => (1 :A :B :C 5) (splice-seq '(1 2 3 4 5) :start 1 :end 3) => '(1 4 5) ``` -------------------------------- ### Block Compilation with local* Source: https://github.com/ruricolist/serapeum/blob/master/README.md Demonstrates using the `local*` macro to achieve block compilation, which is similar to `local` but preserves the last form. This is useful in Lisps lacking native block compilation syntax. ```common-lisp (progn (defun aux-fn-1 ...) (defun aux-fn-2 ...) (defun entry-point ...)) ``` ```common-lisp (local* (defun aux-fn-1 ...) (defun aux-fn-2 ...) (defun entry-point ...)) ``` ```common-lisp (labels ((aux-fn-2 ...) (aux-fn-1 ...)) (defun entry-point ...)) ``` -------------------------------- ### Compare Octet Vectors (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Compares two octet vectors for equality, similar to `string=` for strings. Allows specifying start and end indices for comparison. ```lisp (octet-vector= v1 v2 &key start1 end1 start2 end2) Like `string=` for octet vectors. [View source](octets.lisp#L89) ``` -------------------------------- ### Create Variadic to Unary Function Adapter (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Returns a function that accepts a single argument (a list) and applies the original function `fn` to the elements of that list. This is equivalent to using `curry` with `apply` and effectively converts a variadic function to accept a list. ```lisp (defun variadic->unary (fn) (lambda (args-list) (apply fn args-list))) ``` -------------------------------- ### Local Expansion of defmemo within local (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/README.md Demonstrates the expansion of the `defmemo` macro when used within a `local` form. This shows how `local` enables different expansion strategies, using `labels` and `named-lambda` for local function definitions. ```common-lisp (local (defmemo fibonacci (n) (if (<= n 1) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) (fibonacci 100)) ;; Expands into this very different code (simplified for readability): (let (fn) (labels ((fibonacci (&rest args) (apply fn args))) (let ((memo-table (make-hash-table :test 'equal))) (setf fn (named-lambda fibonacci (&rest args) (multiple-value-bind (result result?) (gethash args memo-table) (if result? result (setf (gethash args memo-table) (apply (lambda (n) (if (<= n 1) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) args)))))) (fibonacci 100)))) ``` -------------------------------- ### Get Pathname Basename (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Extracts the final component of a pathname. For a directory, it returns the directory's name; for a file, it returns the filename including its extension. ```Common Lisp (path-basename pathname) ``` -------------------------------- ### Sequential Initialization with `lret*` in Common Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md This macro is a sequential version of `lret`. It follows the same principle of returning the initial value of the last binding but evaluates bindings in order, similar to `let*`. ```common-lisp (lret* ((x 1) (y (list x))) (setf (car y) 2)) ;; => '(1) ``` -------------------------------- ### Get Car and Cdr of a List in Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md The `car+cdr` function takes a list and returns its first element (car) and the rest of the list (cdr) as two separate values. ```common-lisp (car+cdr list) ``` -------------------------------- ### Create Unary to Variadic Function Adapter (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Returns a function that accepts any number of arguments and calls the original function `fn` with those arguments as a list. This is useful for adapting functions that expect a single list argument to be called variadically. ```lisp (defun unary->variadic (fn) (lambda (&rest args) (funcall fn args))) ``` -------------------------------- ### Non-Splice Sequence (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Removes a part of a sequence between START and END and replaces it with NEW contents. The original sequence and NEW may be modified. If NEW is omitted, elements are removed. ```lisp (nsplice-seq (list 1 2 3 4 5) :new (list :a :b :c) :start 1 :end 1) => (1 :A :B :C 2 3 4 5) (nsplice-seq (list 1 2 3 4 5) :new (list :a :b :c) :start 1 :end 4) => (1 :A :B :C 5) (nsplice-seq (list 1 2 3 4 5) :start 1 :end 3) => '(1 4 5) ``` -------------------------------- ### Define Unbound Parameter with defparameter-unbound (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Similar to `defvar-unbound`, but additionally ensures that the specified variable is unbound when the macro is evaluated. This is useful for guaranteeing a variable starts in an unbound state. ```common-lisp (defparameter-unbound var &body (docstring)) ``` -------------------------------- ### Sequence Manipulation Functions in Serapeum Source: https://github.com/ruricolist/serapeum/blob/master/README.md Demonstrates Serapeum's functions for dividing and organizing sequences, including 'runs', 'batches', 'assort', and 'partition'. These functions are designed for efficiency, return like sequences, and accommodate generic sequences. ```common-lisp (runs '(head tail head head tail)) => '((head) (tail) (head head) (tail)) ``` ```common-lisp (batches (iota 11) 2) => ((0 1) (2 3) (4 5) (6 7) (8 9) (10)) ``` ```common-lisp (assort (iota 10) :key (lambda (n) (mod n 3))) => '((0 3 6 9) (1 4 7) (2 5 8)) ``` ```common-lisp (partition #'oddp (iota 10)) => (1 3 5 7 9), (0 2 4 6 8) ``` ```common-lisp (partitions (list #'primep #'evenp) (iota 10)) => ((2 3 5 7) (0 4 6 8)), (1 9) ``` -------------------------------- ### Split String Into Words/Tokens (Lisp) Source: https://context7.com/ruricolist/serapeum/llms.txt Splits a string into a sequence of words (alphanumeric runs) or tokens (preserving punctuation). It supports specifying start and end bounds for the splitting operation. ```lisp ;; Split into words (alphanumeric runs) (words "Hello, World! How are you?") ;; => ("Hello" "World" "How" "are" "you") (words "user-name_123") ;; => ("user" "name" "123") ;; Tokens preserve punctuation (tokens "Hello, World! How are you?") ;; => ("Hello," "World!" "How" "are" "you?") ;; With start/end (words "prefix [important] suffix" :start 8 :end 18) ;; => ("important") ``` -------------------------------- ### Dispatching with EQL Types using dispatch-caseql Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md The `dispatch-caseql` macro is similar to `dispatch-case` but implicitly wraps types in `eql`. This makes its syntax more akin to `case` than `typecase`, suitable for dispatching on specific eql-bound values. ```common-lisp (dispatch-caseql (&rest exprs-and-types) &body clauses) ``` -------------------------------- ### CLOS Method Combination: `serapeum:standard/context` Source: https://github.com/ruricolist/serapeum/blob/master/README.md Introduces `serapeum:standard/context`, a CLOS method combination that allows an extra `:context` qualifier. Methods with this qualifier run in most-specific-last order and take precedence over other methods, enabling classes to enforce specific dynamic contexts for subclass methods. ```common-lisp (defgeneric my-generic-function (object) (:method-combination serapeum:standard/context)) ``` ```common-lisp (defmethod my-generic-function :context ((o my-class) context-info) ;; Code to run in a specific context before subclass methods) ``` ```common-lisp (defmethod my-generic-function :around ((o my-class)) ;; Standard :around method) ``` ```common-lisp (defmethod my-generic-function ((o my-class)) ;; Standard method implementation) ``` -------------------------------- ### Get Human-Readable File Size in Common Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Formats the size of a given file into a human-readable string using `format-file-size-human-readable`. It first obtains the file size in octets using `trivial-file-size:file-size-in-octets`. ```common-lisp (file-size-human-readable file &key flavor space suffix stream) ``` -------------------------------- ### Substring Counting (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Counts the number of non-overlapping occurrences of a substring within a larger string. The search can be limited to a specific range within the string using start and end parameters. ```common-lisp (string-count "a" "banana") ;; => 3 (string-count "a" "banana" :start 1 :end 4) ;; => 2 ``` -------------------------------- ### Convert List to Set Hash Table (set-hash-table) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Creates a hash table from a list, where elements of the list serve as both keys and values, effectively representing a set. Optional arguments control strictness, hash table test, key transformation, and other properties. Equivalent to Alexandria's alist-hash-table and plist-hash-table for set-like lists. ```common-lisp (set-hash-table set &rest hash-table-args &key test key strict &allow-other-keys) ``` -------------------------------- ### Create Hash Table from Key-Value Sequences (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Populates a hash table with key-value pairs from two sequences. It's similar to `pairlis` but operates on sequences and returns a hash table. By default, it uses `eql` as the hash table test. ```Common Lisp (pairhash keys data &optional hash-table) ``` -------------------------------- ### Get Bound Variable Value in Common Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Returns the value of a symbol if it is bound, along with a T flag. If the symbol is unbound, it returns an optional default value and a NIL flag. This is useful for checking variable states. ```common-lisp (bound-value s &optional default) ``` -------------------------------- ### Partial Application Function (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Implements partial application, returning a new function that, when called, applies the original function `fn` with the provided `args` prepended to any new arguments. This is similar to `alexandria:curry` but is designed to be always inlined. ```Common Lisp (partial fn &rest args) ``` -------------------------------- ### Get First N Elements of a List (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Retrieves the first N elements from a given list and returns them as a new list. This function is useful for taking initial segments of lists without modifying the original. ```common-lisp (defun firstn (n list) (subseq list 0 (min n (length list)))) ``` -------------------------------- ### Get Set from Hash Table (hash-table-set) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Returns the set represented by a hash table, where keys and values are identical. If `strict` is provided, it checks if the table truly represents a set. Without `strict`, it's equivalent to `hash-table-values`. ```common-lisp (hash-table-set hash-table &key strict test key) ``` -------------------------------- ### Dispatch Case QL Let Macro in Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md The `dispatch-caseql-let` macro is a variation of `dispatch-case-let` that utilizes the clause syntax specific to `dispatch-caseql`. It allows for defining bindings within a dispatching context using `dispatch-caseql`'s structure. ```lisp (dispatch-caseql-let (&rest bindings) &body clauses) ``` -------------------------------- ### Render Function Reference as Markdown (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Renders API reference for specified package names of a given system into Markdown format. Output can be directed to a stream, returned as a string, or written to a file. ```lisp (render-function-reference-as-markdown package-names system-name &key stream) ;; ... implementation ... ) ``` -------------------------------- ### Check String Suffix (Case-Sensitive and Insensitive) (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Offers `serapeum:string$=` for case-sensitive suffix checking and `serapeum:string-suffix-p` for case-insensitive suffix checking. These functions also support optional start and end index arguments. ```common-lisp (serapeum:string$= suffix string &key start1 end1 start2 end2) ``` ```common-lisp (serapeum:string-suffix-p suffix string &key start1 end1 start2 end2) ``` -------------------------------- ### Create Dyadic Hook Function (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Defines a dyadic hook function, which takes two functions `f` and `g`. It applies `f` to the first argument `x` and the result of applying `g` to `x`. An example is converting minutes to fractional hours. ```lisp (defun hook2 (f g) (lambda (x y) (funcall f x (funcall g y)))) ``` -------------------------------- ### Create New Hash Table by Mapping (maphash-new) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Creates and returns a new hash table by applying a function to each key-value pair of an existing hash table. The function must return two values: a new key and a new value. Optional arguments can override the properties of the new hash table. ```common-lisp (maphash-new fn hash-table &rest hash-table-args &key &allow-other-keys) ``` -------------------------------- ### Check String Prefix (Case-Sensitive and Insensitive) (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Provides functions `serapeum:string^=` for case-sensitive prefix checking and `serapeum:string-prefix-p` for case-insensitive prefix checking. Both functions allow specifying start and end indices for the prefix and string. ```common-lisp (serapeum:string^= prefix string &key start1 end1 start2 end2) ``` ```common-lisp (serapeum:string-prefix-p prefix string &key start1 end1 start2 end2) ``` -------------------------------- ### Synchronized Execution Block (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Executes a body of code while holding a unique lock associated with an optional object. If no object is provided, it runs as an anonymous critical section. A literal string at the start of the body can be attached to the lock object. ```Common Lisp (synchronized (&optional (object nil objectp)) &body body) ``` -------------------------------- ### Sequential Multiple Value Bindings with `mvlet*` in Common Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md The `mvlet*` macro expands a series of nested `multiple-value-bind` forms, offering a syntax similar to Scheme's `let-values` but with a less nested structure. Each binding consists of a list of variables and an expression to evaluate. ```common-lisp (mvlet* ((minutes seconds (truncate seconds 60)) (hours minutes (truncate minutes 60)) (days hours (truncate hours 24))) (declare ((integer 0 *) days hours minutes seconds)) (fmt "~d day~:p, ~d hour~:p, ~d minute~:p, ~d second~:p" days hours minutes seconds)) ``` -------------------------------- ### Iterate Over Sequence Splits in Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Provides a mechanism to iterate over subsequences of a given sequence that do not satisfy a specified predicate `split-fn`. The body is executed with `left` and `right` bound to the start and end of each such run. An optional `not-at-end?` variable indicates if the run extends to the end of the sequence. ```lisp (do-splits ((left right &optional not-at-end?) (seq split-fn &key (start 0) end from-end) &optional return) &body body) (defun split-sequence-if (fn seq &key (start 0) end from-end) (collecting (do-splits ((l r) (seq fn :start start :end end :from-end from-end)) (collect (subseq seq l r))))) ``` -------------------------------- ### Local Bindings with Top-Level Forms in Lisp Source: https://context7.com/ruricolist/serapeum/llms.txt Enables the use of familiar top-level definition forms (`defun`, `defmacro`, `def`) to create local bindings within a scope. Definitions created with `local` are not visible outside its scope. It supports mutually recursive functions. ```lisp (local (defun helper (x) (* x 2)) (def multiplier 3) (* (helper 5) multiplier)) ;; => 30 ;; helper and multiplier are not visible outside ;; Works with mutually recursive functions (local (defun even? (n) (if (zerop n) t (odd? (1- n)))) (defun odd? (n) (if (zerop n) nil (even? (1- n)))) (even? 10)) ;; => T ``` -------------------------------- ### Create Hash Table with Key-Value Pairs in Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md The `dict` function is a convenient constructor for hash tables. It takes key-value pairs and optionally a test function. If the number of arguments is odd, the first argument is treated as the test function. ```common-lisp (dict &rest keys-and-values) ``` -------------------------------- ### Get Slot Value Safely (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Retrieves the value of a slot in an instance, similar to `slot-value`, but without signaling errors. Returns three values: the slot's value (or nil), a boolean indicating if the slot was bound, and a boolean indicating if the slot exists. Handles `slot-unbound` methods. ```lisp (slot-value-safe instance slot-name &optional default) Like `slot-value`, but doesn't signal errors. Returns three values: 1. The slot's value (or nil), 2. A boolean that is T if the slot exists and *was* bound, 3. A boolean that is T if the slot exists. Note that this function does call `slot-value` (if the slot exists), so if there is a method on `slot-unbound` for the class it will be invoked. In this case the second value will still be `nil`, however. [View source](clos.lisp#L85) ``` -------------------------------- ### Sequence Iteration and Subsequence (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Provides iteration and subsequence manipulation for sequences. `do-each` offers a `dolist`-like iteration. `nsubseq` returns a potentially structure-sharing subsequence that can be modified with `setf`. ```common-lisp (defmacro do-each ((var seq &optional return) &body body) `(dolist (,var ,seq ,return) ,@body)) ``` ```common-lisp (defun nsubseq (seq start &optional end) (subseq seq start end)) ``` -------------------------------- ### Range Function in Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md The `range` function generates a vector of real numbers. It supports one, two, or three arguments for start, stop, and step values, handling various numeric types and optimizing for memory representation. The function is designed for performance and minimal garbage collection pressure. ```lisp (range start &optional stop step) ``` -------------------------------- ### Array Dispatch with Simple Vector - Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md The `with-simple-vector-dispatch` macro optimizes array access by dereferencing the underlying simple vector of a displaced array. It ensures the type is a subtype of `simple-array` and provides `start` and `end` offsets for the original vector's data. This is useful for performance-critical array operations. ```lisp (with-simple-vector-dispatch (&rest types) (var start end) &body body) ``` -------------------------------- ### FIFO Queue Operations in Lisp Source: https://context7.com/ruricolist/serapeum/llms.txt Implements a First-In, First-Out (FIFO) queue data structure with an API inspired by Arc. Provides functions for creation, adding elements (enq, undeq), removing elements (deq), inspection (front, qback, qlen, queue-empty-p), and concatenation (qconc). ```lisp ;; Create a queue (queue 1 2 3) ;; => # ;; Add to end (let ((q (queue 1 2))) (enq 3 q) (qlist q)) ;; => (1 2 3) ;; Remove from front (let ((q (queue 1 2 3))) (values (deq q) (qlist q))) ;; => 1, (2 3) ;; Add to front (like unshift) (let ((q (queue 2 3))) (undeq 1 q) (qlist q)) ;; => (1 2 3) ;; Queue inspection (let ((q (queue 'a 'b 'c))) (list (front q) ; First element (qback q) ; Last element (qlen q) ; Length (queue-empty-p q))) ; Empty check ;; => (A C 3 NIL) ;; Append lists (let ((q (queue 1 2))) (qconc q '(3 4 5)) ; Destructive (qlist q)) ;; => (1 2 3 4 5) ``` -------------------------------- ### Swap Keys and Values in Hash Table (flip-hash-table) in Common Lisp Source: https://context7.com/ruricolist/serapeum/llms.txt The `flip-hash-table` function creates and returns a new hash table where the keys and values of the original hash table are exchanged. It can optionally take a `filter` argument to include only entries where the original key satisfies the predicate. ```lisp (let ((names (dict 1 'one 2 'two 3 'three))) (gethash 'two (flip-hash-table names))) ;; => 2, T ;; With filtering (let ((numbers (dict 1 'one 2 'two 3 'three))) (flip-hash-table numbers :filter #'oddp)) ;; => Hash table with only odd keys: ONE->1, THREE->3 ``` -------------------------------- ### Find Runs of Similar Elements Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Identifies and returns runs of similar elements within a sequence. Arguments like START, END, and KEY are similar to `reduce`. The TEST function determines similarity, with an option to compare against the previous element (`compare-last`). The COUNT argument limits the number of runs returned. ```common-lisp (runs seq &key start end key test compare-last count) ``` -------------------------------- ### Define Place with defplace (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Defines both a place (variable or accessor) and its `setf` expansion in a single form. The body of the macro includes an optional docstring followed by forms, with the last form being a setf-able expression. ```common-lisp (defplace name args &body body) ``` -------------------------------- ### With Thunk Macro Helper (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md A macro-writing utility that simplifies the creation of macros following the `call-with-` style. It helps avoid boilerplate code associated with creating and managing dynamic-extent closures for function calls, optionally allowing the thunk to be named for debugging. ```common-lisp (with-thunk (spec &rest args) &body body) ``` -------------------------------- ### Create Hash Table Access Function (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Generates a function to access a hash table. The generated function can be used for getting values (like `gethash`) or setting values (like `setf gethash`) depending on the arguments provided. It supports strict key checking and default return values. ```Common Lisp (hash-table-function hash-table &key read-only strict key-type value-type strict-types default) ``` -------------------------------- ### String Search and Replace (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Performs search-and-replace operations on strings. `string-replace-all` replaces all occurrences of a substring, while `string-replace` replaces only the first occurrence. Both functions support specifying start and end indices for the search range and an optional stream for output. `string-replace-all` also accepts a count to limit the number of replacements. ```common-lisp (string-replace-all "old" "The old old way" "new" :start 3 :end 6) ;; => "The new old way" (string-replace-all "foo" "foo foo foo" "quux") ;; => "quux quux quux" (string-replace-all "foo" "foo foo foo" "quux" :count 2) ;; => "quux quux foo" (string-replace "old" "The old old way" "new" :start 3 :end 6) ;; => "The new old way" ``` -------------------------------- ### Partial Application in Lisp Source: https://context7.com/ruricolist/serapeum/llms.txt Applies partial arguments to a function, often inlining for efficiency. Useful for creating specialized functions from general ones. More efficient than curry in many scenarios. ```lisp ;; Partial application (funcall (partial #'+ 1 2) 3 4) ;; => 10 (mapcar (partial #'* 2) '(1 2 3 4 5)) ;; => (2 4 6 8 10) ;; More efficient than curry in most cases (defalias double (partial #'* 2)) (double 21) ;; => 42 ``` -------------------------------- ### Slice Sequence with Negative Bounds (Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Extracts a subsequence from a given sequence, similar to `subseq`, but allows negative indices for offsets from the end. If the start and end bounds cross, an empty string is returned. This function also implicitly clamps bounds. Setf of `slice` creates a new sequence, not EQ to the old one. ```lisp (slice seq start &optional end) ``` -------------------------------- ### List Prepending Utilities in Lisp Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md Functions for prepending lists or items to a list. `prepend` concatenates lists in reverse order, while `prependf` provides a modify-macro for destructive prepending. ```common-lisp (prepend &rest lists) Construct and return a list by concatenating LISTS in reverse order. (prepend list-1 list-2) ≡ (append list-2 list-1) [View source](lists.lisp#L64) ``` ```common-lisp (prependf g &rest lists) Modify-macro for prepend. Prepends LISTS to the PLACE designated by the first argument. [View source](lists.lisp#L71) ``` -------------------------------- ### Deflex Macro for Global Lexical Variables (Common Lisp) Source: https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md The `def` macro, a version of `deflex`, defines a top-level global lexical variable with an initial value. It supports documentation strings and can create a backing global variable for efficiency on supporting implementations. It also handles initializing multiple variables if the value is a list starting with `values`. ```Common Lisp (def var &body (&optional val documentation)) ```