简体   繁体   中英

The format function looping over a dotted alist

I am working on a function that transforms an alist into a query parameters. So far it looks like this.

(defun encode-options (opts)
  "Turns an alist into url query parameters."
  (format nil "~{~{~A=~A~}~^&~}" opts))

This works perfectly for alists like ((ab) (cd)) (Resulting in "A=B&C=D" ), but fails for dotted alists like ((a . b) (c . d)) . (Resulting in The value B is not of type LIST. )

My question is: Is it possible to format the dotted alist to give me the expected results and how?

Is it possible to format the dotted alist?

No, format iterates over proper lists.

There are many possible ways to implement what you want. Here I present two of them.

Keep control string, change data

(defun ensure-proper-list (value)
  (typecase value
    (null nil)
    (cons (cons (car value)
                (ensure-proper-list (cdr value))))
    (t (list value))))

Now, you transform the option argument so that all elements are proper lists:

(defun encode-options (options)
  "Turns an alist into url query parameters."
  (format nil
          "~{~{~A=~A~}~^&~}"
          (mapcar #'ensure-proper-list options)))

Keep data, change control string

(defun print-alist (stream data &optional colonp atsignp)
  (declare (ignore colonp atsignp))
  (destructuring-bind (head . tail) data
    (format stream "~A=~A" head (if (consp tail) (first tail) tail))))

With this new format control, print the list as given:

(defun encode-options (options)
  "Turns an alist into url query parameters."
  (format nil
          "~{~/lib:print-alist/~^&~}"
          options))

Note that I added a package prefix lib because without a package, print-alist would be looked up in the user package (aka COMMON-LISP-USER), which in my opinion is rarely what you want. From 22.3.5.4 Tilde Slash: Call Function :

The function corresponding to a ~/name/ directive is obtained by looking up the symbol that has the indicated name in the indicated package. If name does not contain a ":" or "::", then the whole name string is looked up in the COMMON-LISP-USER package.

That's why I would recommend to always mention the package with ~/ directives.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM