LISP - + Method Combination
Modernizing CLOS: The + Method Combination
Section titled “Modernizing CLOS: The + Method Combination”The Common Lisp Object System (CLOS) offers a powerful and unique feature called Method Combination. It allows you to define how multiple methods, all applicable to a single generic function call, should be combined to produce a final result. This tutorial explores the + method combination, a built-in technique for summing the results of applicable methods, which is perfect for tasks like aggregation and scoring.
Core Concept: Defining a Generic Function with + Combination
Section titled “Core Concept: Defining a Generic Function with + Combination”To use the + method combination, you specify it when defining a generic function using defgeneric. All primary methods defined for this generic function are then expected to return a number. CLOS will automatically sum these numbers to produce the final result.
(defgeneric calculate-cost (x y) (:documentation "Calculates a total cost by summing results from specialized methods.") (:method-combination + :most-specific-first))
;; Define a primary method for two numbers. This is one of the methods to be combined.(defmethod calculate-cost ((x number) (y number)) "The base cost is the sum of two numbers." (+ x y))Key Points
Section titled “Key Points”defgeneric: This is where the combination strategy is declared.(defgeneric calculate-cost (x y) ...)defines the function’s signature.:method-combination +: This key part tells CLOS to use the summing combination. Whencalculate-costis called, CLOS finds all applicable primary methods, calls them, and adds their numeric results together.defmethod: This defines a specific implementation for certain parameter types (classes). Notice the method definition itself does not include the+symbol; it just returns a number. The combination logic is handled by the generic function.- Extensibility: The power of this approach is that you can add new methods for different types without changing the original code. For example, we can define how to calculate costs involving strings by considering their length.
Practical Example: A Multi-Type Cost Calculator
Section titled “Practical Example: A Multi-Type Cost Calculator”Let’s build a complete example that calculates a ‘cost’ by adding numbers directly or by using the length of strings. This demonstrates how CLOS dispatches to the correct methods and how + combination aggregates the results.
cost_calculator.lisp
Section titled “cost_calculator.lisp”;; Modern Lisp projects are managed with systems like ASDF and Quicklisp.;; This code can be part of a system defined in a .asd file.
(defpackage #:cost-calculator (:use #:cl) (:export #:calculate-cost))
(in-package #:cost-calculator)
;; 1. Define the generic function with the '+' method combination.(defgeneric calculate-cost (x y) (:documentation "Calculates a total cost by summing results from specialized methods.") (:method-combination + :most-specific-first))
;; 2. Define methods for different type combinations.;; Each method is a 'primary' method and must return a number.
(defmethod calculate-cost ((x number) (y number)) "Adds two numbers." (+ x y))
(defmethod calculate-cost ((x number) (y string)) "Adds a number to the length of a string." (+ x (length y)))
(defmethod calculate-cost ((x string) (y number)) "Adds the length of a string to a number." (+ (length x) y))
(defmethod calculate-cost ((x string) (y string)) "Adds the lengths of two strings." (+ (length x) (length y)))
;; 3. Demonstrate the usage.(defun run-examples () (format t "~&Cost of 10 and 5: ~d" (calculate-cost 10 5)) (format t "~&Cost of 10 and \"test\": ~d" (calculate-cost 10 "test")) ; "test" has length 4 (format t "~&Cost of \"alpha\" and 20: ~d" (calculate-cost "alpha" 20)) ; "alpha" has length 5 (format t "~&Cost of \"hello\" and \"world\": ~d" (calculate-cost "hello" "world")))
;; To run this:;; (cost-calculator:run-examples)Expected Output
Section titled “Expected Output”Cost of 10 and 5: 15Cost of 10 and "test": 14Cost of "alpha" and 20: 25Cost of "hello" and "world": 10Explanation
Section titled “Explanation”When (calculate-cost 10 "test") is called, CLOS identifies that the (number string) method is the most specific match. It calls this single method. The + combination simply returns the result since there is only one applicable method. The real power shines when you have multiple methods contributing, such as from inheritance or multi-methods that are not mutually exclusive.
Best Practices and Common Pitfalls
Section titled “Best Practices and Common Pitfalls”- Type Safety: All primary methods for a
+combined generic function must return a number. Returningnilor any other type will signal aTYPE-ERRORat runtime. - Readability: Use
+combination when the act of summing results is intuitive and clear. For more complex logic, a standard method with:aroundqualifiers might be more maintainable. - Zero Contribution: If a method should contribute nothing to the sum under certain conditions, it should explicitly return
0. - Other Combinations: Explore other built-in combinations like
and,or,list,append, andmaxto see the full power of this CLOS feature. They follow the same principle but perform different operations on the results.