I have wrote a simple util to submit my code to a online judge site, how to avoid the evil function?

(setq url-proxy-services '(("http" . "localhost:8888")))
(setq debug-on-error t)

(require-package 'http-post-simple) 
(require 'http-post-simple)
(eval-when-compile (require 'cl))

(defstruct form action (method "POST") fields)

(defstruct site url forms)

(setq poj (make-site :url "http://poj.org" :forms '(
                            (login .
                                :action "login"
                                :fields `(
                                      (user_id1 . "you-name")
                                      (password1 . ,(read-passwd "input your password: "))
                                      (url . "%2F")
                                      (B1 . "login"))))
                            (submit .
                                 :action "submit"
                                 :fields `(
                                       (problem_id ,(read-string "inpur problem id: "))
                                       (language ,(read-string "select language: 0:G++,1:GCC,2:Java,3:Pascal,4:C++,5:C,6:Fortan "))
                                       (source ,(with-temp-buffer
                                          (insert-file-contents (read-file-name "select source file"))(buffer-string)))
                                       (submit "Submit"))))
                            (logout .
                                 :action "login?action=logout&url=%2F"
                                 :method "GET")))))

(defun http-get-simple(url)
          (let (header data status)
            (url-retrieve-synchronously url)
              (setq status url-http-response-status)
              (goto-char (point-min))
              (if (search-forward-regexp "^$" nil t)
              (setq header (buffer-substring (point-min) (point))
                data   (buffer-substring (1+ (point)) (point-max)))
            (setq data (buffer-string)))
              (kill-buffer (current-buffer)))
              (values data header status)))

(defun request-site(site form)
  "perform a request to site"
  (let* ((url (site-url site))
     (form (cdr (assoc form (site-forms site))))
     (form-inst (eval form))
     (result (if (equal (form-method form-inst) "POST")
             (http-post-simple (concat url "/" (form-action form-inst))
                       (form-fields form-inst))
           (http-get-simple (concat url "/" (form-action form-inst))))))

(defun poj-login()
  (request-site poj 'login))

(defun poj-logout()
  (request-site poj 'logout))

(defun poj-submit()
  (request-site poj 'submit))    

Above is my code, I have tried this

(let* ((form (cdr (assoc 'submit (site-forms poj))))
       (frm-inst (apply (car form) (cdr form)))) ; get weird result
  (eval form)) ; get proper result

And can you give me some advice about coding style?

  • 1
    \$\begingroup\$ please indent your code properly! \$\endgroup\$
    – sds
    Commented Oct 30, 2013 at 15:06

1 Answer 1


The short answer to your question is that forms are evaluated while functions are called (using funcall or apply).

I.e., the way you structure your code (lists of forms) you are painting yourself into the eval corner. You need to replace lists of forms with lists of functions and then you will be able to use funcall or apply.

E.g., replace

`((problem_id ,(read-string "inpur problem id: "))
  (language ,(read-string "select language: 0:G++,1:GCC,2:Java,3:Pascal,4:C++,5:C,6:Fortan "))
  (source ,(with-temp-buffer
            (insert-file-contents (read-file-name "select source file"))
  (submit "Submit"))

with something like

`((problem-id read-string "problem id: ")
  (language read-string "language: 0:G++,1:GCC,2:Java,3:Pascal,4:C++,5:C,6:Fortan ")
  (source ,(lambda () (file-to-string (read-file-name "source file: "))))
  (submit identity "Submit"))

Where file-to-string is defined thus:

(defun file-to-string (file)
  "Read the content of FILE and return it as a string."
    (insert-file-contents file)

Now you can replace (eval form) with (apply (car form) (cdr form)).

  • \$\begingroup\$ Use lambda can't get right result, because cl-defstruct will wrap list with list, it's so weird. Thanks for your answer, it a good clue. \$\endgroup\$
    – Frei Zhang
    Commented Nov 1, 2013 at 9:00
  • 1
    \$\begingroup\$ @ifree: you should use defstruct-defined accessors instead of car/cdr. \$\endgroup\$
    – sds
    Commented Nov 1, 2013 at 13:14

Your Answer

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

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