Что не так со следующим макросом языка Common LISP, использующим gensym?

URL имеет встроенный редирект. Обычно такие перенаправления, особенно для URL-адресов, предназначенных для браузеров (которые явно не являются URL-адресами в формате mp3), передаются как HTTP 301 «Перемещено навсегда» (а иногда и 302 «Перемещено временно»), при этом правильный URL-адрес отправляется в Location заголовок. Текст, который вы видите (загруженные вами 315 байт), является просто «запасным» HTML-кодом, в котором также указано, что содержимое было перемещено. К счастью, нет необходимости разбирать это.

HTTP-браузер кода openStream URL-адреса является очень простым и не следует перенаправлениям. Вам нужен API, который делает. URLConnection (также из основных библиотек) может это сделать, но он не следует перенаправлениям, если перенаправление переключается с http на https или наоборот, поэтому вы можете этого не делать. На всякий случай, если вы это сделаете:

File target = /*...*/;
HttpURLConnection con = (HttpURLConnection) new URL(link).openConnection();
con.setInstanceFollowRedirects(true);
try (InputStream in = con.getInputStream()) {
    Files.copy(in, target.toPath(), StandardCopyOption.REPLACE_EXISTING);
}

Если вышеприведенное не принесло пользы (возможно, из-за проблемы с перенаправлением HTTP / HTTPS), я предлагаю выбрать реального HTTP-клиента, которого стандартный API не предоставляет. Я предлагаю OkHttp .

10
задан pupeno 15 May 2009 в 11:04
поделиться

5 ответов

Использовать DO* вместо DO.

DO Инициализирует привязку в объеме, где они еще не видимы. DO* инициализирует привязку в объеме, где они видимы.

В данном случае var потребности сослаться на другую привязку loop-start.

5
ответ дан 3 December 2019 в 23:52
поделиться

Вам на самом деле не нужно gensym здесь для предотвращения переменного получения, потому что Вы не представляете переменных, которые были бы "локальны для макроса". Когда Вы макроразворачиваете Ваш do-primes-v2, Вы будете видеть, что никакая переменная не представлена, который не существовал за пределами макроса.

Вам действительно нужен он для другой вещи, хотя: уход от нескольких оценка.

Если Вы называете макрос как это:

(do-primes-v2 (p (* x 2) (* y 3))
  (format "~a~%" p))

это расширяется до

(do ((p (if (is-prime (* x 2))
            (* x 2)
            (next-prime-after (* x 2))
        (next-prime-after p)))
    ((> p (* y 3))
  (format "~a~%" p))

В лучшем случае это неэффективно, потому что то умножение сделано многократно. Однако, если Вы используете функцию с побочными эффектами как исходные данные, как setf или incf, это может быть большой проблемой.

4
ответ дан 3 December 2019 в 23:52
поделиться

Или переместите привязку своего запуска цикл, и конец цикла включению ПОЗВОЛИЛ блоку или использует DO*. Причина состоит в том, что все переменные цикла в ДЕЛАЮТ связываются "параллельно", таким образом, для первой привязки, (расширенная) переменная запуска цикл еще не имеет привязки.

3
ответ дан 3 December 2019 в 23:52
поделиться

Я знаю, что это действительно не отвечает на Ваш вопрос, но я действительно думаю, что это релевантно. По моему опыту, тип макроса, который Вы пытаетесь записать, является очень общим. Одна проблема, которую я имею со способом, которым Вы приблизились к проблеме, состоит в том, что это не обрабатывает другой случай общего использования: функциональный состав.

У меня нет времени для выделения некоторых трудностей, Вы, вероятно, встретитесь с использованием Вашего макроса, я однако выделю это, имел Вас, создал Ваш главный итератор, приспособленный к функциональному составу, Ваш макрос оказывается чрезвычайно простым, избегая Вашего вопроса в целом.

Примечание: Я немного изменил некоторые Ваши функции.

(defun is-prime (n)
  (cond
    ((< n 2)
     nil)
    ((= n 2)
     t)
    ((evenp n)
     nil)
    (t
     (do ((i 2 (1+ i)))
     ((= i n) t)
       (when (or (= (mod n i) 0))
         (return nil))))))

(defun next-prime (n)
  (do ((i n (1+ i)))
      ((is-prime i) i)))

(defun prime-iterator (start-at)
  (let ((current start-at))
    (lambda ()
      (let ((next-prime (next-prime current)))
         (setf current (1+ next-prime))
         next-prime))))

(defun map-primes/iterator (fn iterator end)
  (do ((i (funcall iterator) (funcall iterator)))
      ((>= i end) nil)
    (funcall fn i)))

(defun map-primes (fn start end)
  (let ((iterator (prime-iterator start)))
    (map-primes/iterator fn iterator end)))

(defmacro do-primes ((var start end) &body body)
  `(map-primes #'(lambda (,var)
                   ,@body)
               ,start ,end))

Я также рекомендую посмотреть на Ряд. Шаблон генератора является также очень обычным явлением в программах шепелявости. Можно также хотеть посмотреть на Александрию, в особенности функциональный ALEXANDRIA:COMPOSE для наблюдения, какой интересный материал можно сделать с функциональным составом.

1
ответ дан 3 December 2019 в 23:52
поделиться

Я предлагаю избежать, ДЕЛАЮТ* и макросы в целом и вместо этого идущий для Ряда (реализация которого может быть найдена на series.sourceforge.net).

Если это слишком сложно, затем рассматривают просто генерацию списка начал с рекурсией или генератором (для поколения по запросу).

0
ответ дан 3 December 2019 в 23:52
поделиться