11

My embarrassingly easy question is the following:

Why does the following code works:

(require 'request)

(defun geocoder ()
  (request
   "http://rpc.geocoder.us/service/csv"
   ;;; **Hardcoded parameter!**
   :params '(("address" . "1600 Pennsylvania Ave, Washington DC"))
   :parser 'buffer-string
   :success (function*
             (lambda (&key data &allow-other-keys)
                (when data
                (with-current-buffer (get-buffer-create "*request demo*")
                  (erase-buffer)
                  (insert data)
                  (pop-to-buffer (current-buffer))))))
   :error
   (function* (lambda (&key error-thrown &allow-other-keys&rest _)
                (message "Got error: %S" error-thrown)))
   ))

(geocoder)

While this one doesn't?

(require 'request)

(defun geocoder (address) ;; adding a parameter!
  (request
   "http://rpc.geocoder.us/service/csv"
   :params '(("address" . address))
   :parser 'buffer-string
   :success (function*
             (lambda (&key data &allow-other-keys)
                (when data
                (with-current-buffer (get-buffer-create "*request demo*")
                  (erase-buffer)
                  (insert data)
                  (pop-to-buffer (current-buffer))))))
   :error
   (function* (lambda (&key error-thrown &allow-other-keys&rest _)
                (message "Got error: %S" error-thrown)))
   ))

;;; Now with parameter!
(geocoder "1600 Pennsylvania Ave, Washington DC")

How should I send a parameter to request?

1 Answer 1

14

This is because '(("address" . address)) is quoted (i.e. prefixed by the ' operator), which means that what is inside does not get evaluated. The request function thus gets called with an argument which is the unevaluated address symbol (whereas in your first implementation, the request function gets a string litteral, which doesn't need to be evaluated first).

You can fix this in 2 ways:

1) quasi-quoting the argument, which allows you to get mostly the same behaviour but to specify parts which still need to be evaluated:

`(("address" . ,address))

Note that the single quote (') has been replaced by a backquote (`), and a special marker , was added before address to indicate that it should be evaluated and substituted with its value.

2) (as per @JordonBiondo's comment) building the structure explicitly using primitives such as list or cons. In your case, this would be done like this:

(list (cons "address" address))

where, again, "address" is a string literal (which evaluates to itself), and address gets evaluated since it is the argument in a function call.

4
  • Thanks for the explanation. It is improving, but now I get "Wrong type argument: integerp, \," :(
    – baol
    Oct 5, 2015 at 18:08
  • Ah, ok: gnu.org/software/emacs/manual/html_node/elisp/Quoting.html that is a backquote!!
    – baol
    Oct 5, 2015 at 18:28
  • 1
    I added links to relevant parts of the manual to make it clearer. And I also explicitly mentioned the backquote since it unsurprisingly wasn't that obvious at first sight... Oct 5, 2015 at 18:41
  • 6
    alternatively you could write that as (list (cons "address" address)) if you don't want to use backticks Oct 5, 2015 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.