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 .
Использовать DO*
вместо DO
.
DO
Инициализирует привязку в объеме, где они еще не видимы. DO*
инициализирует привязку в объеме, где они видимы.
В данном случае var
потребности сослаться на другую привязку loop-start
.
Вам на самом деле не нужно 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
, это может быть большой проблемой.
Или переместите привязку своего запуска цикл, и конец цикла включению ПОЗВОЛИЛ блоку или использует DO*. Причина состоит в том, что все переменные цикла в ДЕЛАЮТ связываются "параллельно", таким образом, для первой привязки, (расширенная) переменная запуска цикл еще не имеет привязки.
Я знаю, что это действительно не отвечает на Ваш вопрос, но я действительно думаю, что это релевантно. По моему опыту, тип макроса, который Вы пытаетесь записать, является очень общим. Одна проблема, которую я имею со способом, которым Вы приблизились к проблеме, состоит в том, что это не обрабатывает другой случай общего использования: функциональный состав.
У меня нет времени для выделения некоторых трудностей, Вы, вероятно, встретитесь с использованием Вашего макроса, я однако выделю это, имел Вас, создал Ваш главный итератор, приспособленный к функциональному составу, Ваш макрос оказывается чрезвычайно простым, избегая Вашего вопроса в целом.
Примечание: Я немного изменил некоторые Ваши функции.
(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 для наблюдения, какой интересный материал можно сделать с функциональным составом.
Я предлагаю избежать, ДЕЛАЮТ* и макросы в целом и вместо этого идущий для Ряда (реализация которого может быть найдена на series.sourceforge.net).
Если это слишком сложно, затем рассматривают просто генерацию списка начал с рекурсией или генератором (для поколения по запросу).