Search code examples
lispcommon-lisp

how can I modify this function to create a dynamic plist


What I'm trying to do: I want to define a function create-record that accepts a variable number of parameters (names called keys) and generates a dynamic plist/named list.

I'm just trying to get it working with dynamic names first and assign 1 to all the names to create a list like (:x 0 :y 0 :z 0) then I can modify it to accept both keys and values (instead of just 0 for everything key)

My code:

(defparameter *test* '('x 'y 'z))
(defun create-record (&rest keys) 
  (let ((count 0))
    (mapcan (lambda (key) (list key count)) keys)))

Output

(create-record-variable *test*)
==>  (('X 'Y 'Z) 0)

Expected Output:

(create-record-variable *test*)
==> (:x 0 :y 0 :z 0)

I'm not sure why the output is like (('X 'Y 'Z) 0).


Solution

  • The problem is not with the function, but with the invocation. What you need to do is

    (create-record 'a :b '#:c)
    ==> (A 0 :B 0 #:C 0)
    

    or, if the keywords are in a list,

    (defparameter *test* '(:x :y :z))
    (apply #'create-record *test*)
    ==> (:X 0 :Y 0 :Z 0)
    

    If you want to pass the list as the argument, you can just drop &rest.

    Answering the question in the comment, here is how to create an alist (association list):

    (defun make-alist (keys values)
      (mapcar #'cons keys values))
    (defparameter *my-alist* (make-alist '(:a :b :c) '(1 2 3)))
    (assoc :a *my-alist*)
    ==> (:A . 1)
    

    and a plist (property list):

    (defun make-plist (keys values)
      (mapcan #'list keys values))
    (defparameter *my-plist* (make-plist '(:a :b :c) '(1 2 3)))
    (getf *my-plist* :b)
    ==> 2