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?

baol
  • 231
  • 1
  • 8

1 Answers1

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.

François Févotte
  • 5,917
  • 1
  • 24
  • 37
  • Thanks for the explanation. It is improving, but now I get "Wrong type argument: integerp, \," :( – baol Oct 05 '15 at 18:08
  • Ah, ok: http://www.gnu.org/software/emacs/manual/html_node/elisp/Quoting.html that is a backquote!! – baol Oct 05 '15 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... – François Févotte Oct 05 '15 at 18:41
  • 6
    alternatively you could write that as `(list (cons "address" address))` if you don't want to use backticks – Jordon Biondo Oct 05 '15 at 19:13