Skip to content

Tutorial 2: Optional, Keyword and Rest Arguments

Mark Cox edited this page Nov 12, 2017 · 1 revision

The defstore macro allows users to specify optional, keyword and rest arguments in the store lambda list using the familiar lambda list keywords, &optional, &key and &rest. More formally, the store-lambda-list argument must adhere to the following syntax.

store-lambda-list ::= (var*
                       [&optional {var | (var [init-form [supplied-var-p]])}*]
                       [&rest var]
                       [&key {var | ({var | (keyword-name var)} [init-form [supplied-var-p]])}* [&allow-other-keys]]

Example store function definitions using the above syntax are

;; Optional arguments
(defstore my-function (a b &optional c))
(defstore my-function (a b &optional (c init-form)))
(defstore my-function (a b &optional (c init-form c-p) (d c-p)))

;; Keyword arguments
(defstore my-function (a &key b))
(defstore my-function (a &key (b init-form)))
(defstore my-function (a &key ((:hello b) init-form b-p) (c b-p)))

;; Rest arguments
(defstore my-function (a &rest args))

Optional and Keyword Arguments

The values bound to optional, keyword and rest arguments of store functions are used to select the most applicable specialization. This design choice requires the store function to evaluate the initialization forms of unspecified optional and keyword arguments.

The algorithm for selecting the most applicable specialization for store functions specifying either optional and keyword arguments, or optional arguments without a rest argument, is identical to the algorithm outlined for the fixed arity function in Tutorial 1.

Examples of specializations for optional and keyword arguments are as follows.

;; y := a x + b y
(defstore nxpy (y x &optional (a 1) (b 1)))
(defspecialization nxpy ((y sequence) (x sequence) (a number) (b number)) (values)
  (map-into y (lambda (y-i x-i)
                (+ (* b y-i) (* a x-i)))
            y x))

;; y := Hadamard_product(a x, y)
;; or
;; y-i := a x-i y-i
(defstore nhadamard-product (y x &key (a 1)))
(defspecialization nhadamard-product ((y sequence) (x sequence) &key (a number)) (values)
  (map-into y (lambda (y-i x-i)
                (* a y-i x-i))
              y x))

The keyword section of a specialization-lambda-list given to defspecialization must have the same order as the store function. Users can specify keyword arguments other than those specified in the store function, however, these arguments are not considered when selecting the most applicable specialization.

(defstore nhadamard-product (y x &key (a 1)))
(defspecialization nhadamard-product ((y number) (x number) &key (a number) (b "hello")) t
  (list y x a b))

(nhadamard-product 1 2) => (1 2 1 "hello")
(nhadamard-product 3 4 :b "garbage" :allow-other-keys t) => (3 4 1 "garbage")

Note in the example above that the keyword argument b is not found in the lambda list of the nhadamard-product store function. This results in the form "hello", found in the specialization lambda list, being interpreted as an initialization form rather than a type.

Rest Arguments

The specialization store system also provides support for dispatching according to the values collated in a rest argument. This functionality is only applicable to store functions containing a rest argument without keyword arguments.

;; y = x1 + x2 + ... + xN
(defstore add (&rest args))

(defspecialization add () (eql 0)
  0)

(defspecialization add ((x1 number)) number
  x1)

(defspecialization add ((x1 number) (x2 number)) number
  (+ x1 x2))

(defspecialization add ((x1 number) (x2 number) (x3 number) &rest (args number)) number
  (apply #'add (add x1 x2) x3 args))

(add) => 0
(add 1) => 1
(add 1 2) => 3
(add 1 2 3) => 6
(add 1 2 3 4 "hello") => signals error

The presence of the rest argument in the add store function does not change the algorithm used to select the most applicable specialization. The algorithm remains the following:

  1. Remove specializations that are not applicable.
  2. Remove specialization x with domain X if there exists another specialization whose domain is a subset of X.
  3. Apply one of the remaining specializations.
Clone this wiki locally