LINUX.ORG.RU

Allegro CL 9.0 Free Express Edition стал доступен для загрузки

 ,


9

10

Для загрузки на попробовать стала доступна версия коммерческой реализации языка программирования Common Lisp — Allegro CL 9.0 Express Edition.

Доступны пакеты для:

  • Linux (glibc 2.11 или позже);
  • Mac OS X (10.6 или позже), включает поддержку Lion;
  • FreeBSD (8.2 или позже);
  • Windows (XP, Vista, 7, 8, Server).

Основные новшества и изменения в этой версии:

  • полная поддержка SMP;
  • 820 исправлений и улучшений с последнего релиза;
  • полностью обновлен AllegroServe — вебсервер Franz Inc., написанный на лиспе: автоматическая компрессия/декомпрессия файлов, поддержка chunking, новый выбор опций безопасности, включая TLS v1.0 (также известный как SSL v3.1) протокол для защищенных соединений;
  • улучшена интеграция с Java через модуль jLinker, улучшен протокол, стал проще API;
  • новая и значительно упрощенная инсталляция для графических утилит на Mac 64-бит.

>>> Загрузка

★★

Проверено: anonymous_incognito ()
Последнее исправление: tazhate (всего исправлений: 4)

Ответ на: комментарий от mv

А можно привести пример использования лексического контекста, биндингов и source location в гигиеничесом макросе?

Ну просто пример использования source location:

(define-syntax-rule (yoba error-expression) error-expression)
(yoba (+ 1 "1"))
в данном случае ошибка в выражении "(+ 1 «1»)" - Dr.Racket кинет эксепшн, выделит этот кусок выражения няшной розовой рамочкой в тексте исходного файла и укажет его позицию (2 строка, 7 символ). Эта информация, в частности, используется в дебагере - когда выполняете код, то дебагер прыгает на исполняемое выражение и выделяет его. Оно же используется для вывода значений переменных, если мышкой навести. Ну и вообще эта информация нужна для отладки и корректного вывода ошибок.

Ну или хотя бы объяснить, что в макросе понимается под лексическим контекстом, откуда на стадии макроэскандинга взялись биндинги

Лексический контекст - это и есть биндинги (упрощенно говоря, есть некоторые ньюансы, но вам они непринципиальны)

и что делать с source location, если в следующей форме есть макрос, который этот самый source перекроит?

Ну вообще говоря он конечно может перекроить, если вы сами намеренно взяли и перекроили. Вот такой пример:

(define-syntax-rule (yoba x y)
  (begin (+ x y)))

(yoba 1 "2")
в этом случае ошибка в выражении "(+ x y)" и именно его и подсветит, то есть именно в самом определении макроса а не в точке вызова. Нам это неудобно, следуя логике ошибка в этом выражении это по сути ошибка в выражении всего макроса, так что было бы естественным подсвечивать и указывать позицию выражения "(yoba 1 «2»)", поэтому мы можем в макросе поменять позицию выражения "(+ x y)" на позицию выражения "(yoba 1 «2»)".

откуда на стадии макроэскандинга взялись биндинги (информация из рантайма, в общем-то)

Ну потому что это информация из компайлтайма, точнее из первой фазы :)

(рантайма/компайлтайма нет - есть фазы, при чем они относительные. 0 - текущая, есть -1, 2, -2, 2 и так далее до +- бесконечностей).

Благодаря этому можно сравнивать идентификаторы по их биндингу и в частности реализовать нормальный макростепер - в нем все связанные переменные красивенько подсвечиваются и т.п. вдобавок любой синтакс. объект хранит весь свой «путь» (через какие макросы проходил) это позволяет при отладке макросов скрывать те или иные группы макросов, раскрывая остальные. Еще синтакс. объекты могут хранить произвольные свойства.

То есть вообще, если экспандер видит несвязанную переменную, он дает ошибку «unbound variable». Отсюда следует, что рекурсивные определения невозможны, но на самом деле они возможны благодаря тому, что экспандер в некотором смысле двухпроходной. Что очень сильно повышает выразительность макросистемы, кстати, позволяя произвольные forward-declarations, то есть можно вызывать макрос, который не определен в точке вызова, но определен где-то там ниже. С макросами это не так важно, а вот если мы хотим связать раскрытие макроса с произвольной статической информацией (например как match связан с объявлениями struct), то очень полезно.

anonymous
()
Ответ на: комментарий от mv

Развернётся в let ... if, в котором для вычисления it будет использоваться предыдущий биндинг it.

Для вычисления. А для подстановки будет использован новый it. Там внутри будет выражение (if it it it) причем первый и третий it - это «новые» и тут все логично, т.к. они вводятся макросом, а вот второй it, который будет выведен результатом, введен макропользователем, который не ожидал переопределения и ожидал возврата 3, в то время как общелисп вернет 4.

То есть человек определил it неким образом, а макрос, в который разворачивается используемый им макрос, этот it переопределяет, что совершенно неожиданно, если ты не в курсе, что твой макрос раскроется в aif (а с чего бы пользователю быть в курсе, во что раскрывается макрос?).

anonymous
()
Ответ на: комментарий от anonymous
(define-simple-macro (helper path ...)
  #:do [(define p (for/list ([x (syntax->datum #'(path ...))])
                    (case x [(car) #\a] [(cdr) #\d])))] 
  #:with name (syntax-local-introduce (datum->syntax #'this (string->symbol (list->string `(#\c ,@p #\r)))))
  (define (name lst) (helper2 (path ...) lst)))

(define-syntax (helper2 stx)
  (syntax-parse stx
    [(_ () lst) #'lst]
    [(_ (f ... l) lst) #'(helper2 (f ...) (l lst))]))

(begin-for-syntax
  (define-simple-macro (paths lst ...)
    #:with (id ...) (generate-temporaries #'(lst ...)) 
    (for*/list ([id lst] ...) (list id ...))))

(define-simple-macro (gen)
  #:do [(define p (list #'car #'cdr))]
  #:with (((car-cdr ...) ...) ...) (list (paths p p) (paths p p p) (paths p p p p))
  (begin (helper car-cdr ...) ... ...))

Очень сложно. Слишком много деталей. Леса за деревьями не видно. Другой анонимус привёл простой пример реализации на тупом defmacro, который _на практике_ скорее всего (никаких, конечно, гарантий) будет нормально работать.

При чем тут генсим? 99% мест где нужна гигиена генсимом не покрываются. (define-syntax-rule (yoba x y) (+ x y)) - давай попробуй с генсимом гарантировать, что никто не переопределит + в области вызовы yoba.

Я бы и не пытался ничего гарантировать. Простые косяки, от которых защищает гигиена, и так на тестах вылезут. Я всё-таки не софт для атомных реакторов пишу и мне кажется, что гигиенические макросы — такая же стрельба из пушки по воробьям, как и использование Coq вместо какого-нибудь ML.

Но, вообще, у меня нет богатого опыта использования сложных макросов. Мои use-case, скорее всего, намного проще ваших. Лисп — не один из моих основных рабочих инструментов. Я только к нему присматриваюсь, т.к. задумываюсь о макросах лиспа каждый раз, как начинаю лепить очередное монстроподобное поделие на функторах и довольно сложном в использовании препроцессоре в OCaml :-)

mrm
()
Ответ на: комментарий от mrm

Я догадываюсь, что гигиену без defmacro реализовать на порядок сложнее, чем строить гигиену поверх тупых макросов (которые тривиально реализуются). По такому критерию (что нужно реализовать в первую очередь) defmacro фундаментальнее.

Вы немного не поняли суть. Гигиену нельзя построить «поверх тупых макросов». Придется просто взять и выкинуть старый экспандер с изрядным куском рантайма, после чего практически с нуля написать новый. То есть попытка предварительной реализации defmacro не имеет смысла как таковая.

anonymous
()
Ответ на: комментарий от anonymous

а в твоей общелисповой уже не могу

в этом случае легко можно, если yoba нормально написан:

(defmacro yoba (x)
  (let ((val-1 (gensym)))
    `(let ((,val-1 ,x))
       (aif (+ ,val-1 1) ,val-1 it))))
anonymous
()
Ответ на: комментарий от anonymous

Вы немного не поняли суть. Гигиену нельзя построить «поверх тупых макросов». Придется просто взять и выкинуть старый экспандер с изрядным куском рантайма, после чего практически с нуля написать новый. То есть попытка предварительной реализации defmacro не имеет смысла как таковая.

Смысл в том, что мы строим компилятор постепенно. Нет ещё никакого сложного гигиенического экспандера с фазами и прочими монадизмами. Сначала реализуем тупой defmacro, т.к. это полезный инструмент, нам с помощью него нам проще будет реализовать сложный экспандер с гигиеной. А в какой-то момент мы сможем выкинуть этот defmacro из ядра и забустрапить всё на гигиеничном экспандере.

Я просто рассуждаю вслух, не принимайте близко к сердцу :-) Мне интересно, в чём проблемы такого подхода.

mrm
()
Ответ на: комментарий от mrm

Очень сложно. Слишком много деталей.

Каких деталей? Реализация изрядно проще чем вариант на общелиспе.

Другой анонимус привёл простой пример реализации на тупом defmacro

Простой пример реализации? Вот честно скажу - минут 5 провтыкал в ту анальную акробатику со строками и buf, но так и не понял как оно работает.

Собственно давайте ближе к сути, там макрос состоит из двух частей - генерация всех возможных комбинаций car/cdr и генерация дефайна из каждой из них. Первая часть задачи занимает 1/2 всего макроса, при чем эта часть задачи от макросистемы не зависит, ее можно реализовать и так и эдак (то есть мой вариант можно перевести на общелисп, а варинат общелиспа на Racket). Вторая часть задачи генерит дефайн - и эта часть тоже может полностью совпадать, единственная разница лишь в том, что в моем варианте к сгенерированному символу для имени функции надо применить syntax-local-introduce/datum->syntax. Это (применение функции) ЕДИНСТВЕННАЯ разница, которая обязана быть, все остальное можно сделать как в реализации для SBCL. Другое дело что в общемакросах принято (и все привыкли) пидорасить списки на низком уровне, а в racket идеоматический путь - делать все на паттернах. Хотя можно и руками, но принято на паттернах. Потому что декларативно и ясно - глянув на паттерн сразу видно какая у макроса форма вызова и куда он раскрывается (если посмотерть на тело). А когда там петушня типа `(blah blah ,@(do blah-blah)), то пока вы не отпарсите и не поймете как и что происходит в do, то и результат работы макроса не ясен.

Я бы и не пытался ничего гарантировать. Простые косяки, от которых защищает гигиена, и так на тестах вылезут.

В том и дело что не вылезут. Такие вещи как вариант с aif или с переопределением плюса можно будет словить только очень-очень поздно, причем скорее всего это все будет в macro-generated коде и вы будете долго и нудно изучать выблев экспандера. Это как раз значительный плюс гигиены - с ней макрос либо вообще никак не раскрывается, либо работает правильно.

anonymous
()
Ответ на: комментарий от mrm

Но пример хороший. У меня какой-то совсем сложный aif получился, даже показывать не хочу :-) Это из-за недостатка опыта.

Вообще, и тот аиф что я написал - тоже неидеальный аиф (хотя и значительно лучше чем в CL). Для _совсем правильного аифа с блекджеком и шлюхами_ я бы использовал синтаксические параметры (это штука которую специально сделали для написания анафорических макросов), что усложнит реализацию. Но его на общелиспе уже не повторить даже близко :)

Не совсем тупо. Нужно знать про всякие syntax-local-introduce и ворох других трансформеров.

Надо просто знать семантику макросистемы, более ничего. В общелиспе тоже не так все гладко с его eval-when, например. Я бы сказал что это общая проблема лиспов - чтобы хорошо владеть лиспом, надо очень хорошо понимать семантику низлежащей лисп-машины.

Но меня интересует — во всех ли случаях имеет смысл использовать гигиену?

Вопрос немного некорректен. По сути гигиену нужно использовать _всегда_, и только _в некоторых редких случаях_ надо ее обходить. Именно по-этому гигиена работает по умолчанию. Если бы дело было наоборот (то есть в некоторых редких случаях гигиена нужна а в основном без нее) то тогда по умолчанию гигиены не было бы но ее можно было бы вводить.

Мне сложно работать с ней, думать больно много приходится.

Она нужна именно за тем чтобы не думать :)

Можно привести несколько случаев, когда вам надо было обходить гигиену? Возможно, я смогу привести пару идеоматических решений, которые снимут подобные проблемы :)

anonymous
()
Ответ на: комментарий от anonymous

в этом случае легко можно, если yoba нормально написан:

А йоба как раз нормально написан. Во-первых понятное дело, что лучше иметь возможность правильно написать один единственный aif, чем потом переписывать каждый раскрывающийся в него макрос (так же можно сказать что «а нехуй йобу вызывать не в том контексте»). А во-вторых - действительно только в этом случае. Если немного его усложнить все будет значительно хуже.

anonymous
()
Ответ на: комментарий от mrm

Нет ещё никакого сложного гигиенического экспандера

Насколько я понимаю того анонима, вместо решения с gensymом гигиена хочет это делать автоматом, только вместо экспандера нужен кодволкер и соответственно лексическая информация. Допустим, где-то в макрос передали body, в макросе есть свои биндинги, и чтобы избежать конфликтов кодволкер смотрит body и соответсвующий лексический контекст, а потом пытается что-то там решить/выдать ошибку.

В итоге усложняется все на порядок, а судя по однострочнику с реализацией обычных макросов толком и не работает. А в CL, например, можно обернуть defun макросом с реализацией передачи контекста. И всё будет работать, а приписывать реализацию не нужно.

anonymous
()
Ответ на: комментарий от anonymous

Ты не то сравниваешь. Вот вариант на общелиспе:

;;;; list hackery

;;; Translate CxR into CAR/CDR combos.
(defun source-transform-cxr (form)
  (if (/= (length form) 2)
      (values nil t)
      (let* ((name (car form))
             (string (symbol-name
                      (etypecase name
                        (symbol name)
                        (leaf (leaf-source-name name))))))
        (do ((i (- (length string) 2) (1- i))
             (res (cadr form)
                  `(,(ecase (char string i)
                       (#\A 'car)
                       (#\D 'cdr))
                    ,res)))
            ((zerop i) res)))))

;;; Make source transforms to turn CxR forms into combinations of CAR
;;; and CDR. ANSI specifies that everything up to 4 A/D operations is
;;; defined.
(/show0 "about to set CxR source transforms")
(loop for i of-type index from 2 upto 4 do
      ;; Iterate over BUF = all names CxR where x = an I-element
      ;; string of #\A or #\D characters.
      (let ((buf (make-string (+ 2 i))))
        (setf (aref buf 0) #\C
              (aref buf (1+ i)) #\R)
        (dotimes (j (ash 2 i))
          (declare (type index j))
          (dotimes (k i)
            (declare (type index k))
            (setf (aref buf (1+ k))
                  (if (logbitp k j) #\A #\D)))
          (setf (info :function :source-transform (intern buf))
                #'source-transform-cxr))))
(/show0 "done setting CxR source transforms")
а то что ты написал будет так:
(define-simple-macro (car-n n name)
  #:with name (syntax-local-introduce (format nil "~:r" (syntax->datum #'n)))
  #:with form (for/fold ([res #'lst]) ([i (sub1 (syntax->datum #'n))])
                #`(cdr #,res))
  (define (name lst) (car form)))

anonymous
()
Ответ на: комментарий от anonymous

Насколько я понимаю того анонима, вместо решения с gensymом гигиена хочет это делать автоматом

При чем тут генсим-то? Гигиена никак не связана с генсимом.

А в CL, например, можно обернуть defun макросом с реализацией передачи контекста. И всё будет работать, а приписывать реализацию не нужно.

Нет, не будет. и реализацию придется переписать :(

а судя по однострочнику с реализацией обычных макросов толком и не работает.

По какому однострочнику? Что не работает? Снятие гигиены с символа делается простым применением syntax-local-introduce. Все. Больше ничего не надо.

anonymous
()
Ответ на: комментарий от mrm

Сначала реализуем тупой defmacro, т.к. это полезный инструмент, нам с помощью него нам проще будет реализовать сложный экспандер с гигиеной. А в какой-то момент мы сможем выкинуть этот defmacro из ядра и забустрапить всё на гигиеничном экспандере.

А, ну в плане бустрапа, конечно, можно. Я просто не думаю, что defmacro при бустрапе будет сильно полезным инструментом, который ощутимо поможет в реализации фаз и онадизмов :)

anonymous
()
Ответ на: комментарий от anonymous

Во-первых понятное дело, что лучше иметь возможность правильно написать один единственный aif, чем потом переписывать каждый раскрывающийся в него макрос (так же можно сказать что «а нехуй йобу вызывать не в том контексте»). А во-вторых - действительно только в этом случае. Если немного его усложнить все будет значительно хуже.

Да ты и так всё переусложнил. Либо используем gensym( хоть там внутри aif, let и т.д.), либо объявляем частью интерфейса. В CL все просто и понятно, в отличии от.

anonymous
()
Ответ на: комментарий от anonymous

либо объявляем частью интерфейса

частью какого интерфейса?

Да ты и так всё переусложнил.

Посмотри на мою реализацию yoba и на свою реализацию yoba. У кого она сложнее, лол? И это еще простенький случай, тем сложнее макрос - тем больше будет выигрыш в случае гигиены. Вплоть до того момента, когда на общелиспе вообще не получится написать нормальное решение.

Либо используем gensym( хоть там внутри aif, let и т.д.)

Ну попробуй использовать генсим внутри aif.

В CL все просто и понятно

Оставит тот момент, что в CL ничего не работает. Чем реализация CL «проще и понятнее»?

Ах, да, уже придумал как мне гарантировать, что во внешнем контексте не перекроют плюс и он не станет минусом?

anonymous
()
Ответ на: комментарий от anonymous

При чем тут генсим-то? Гигиена никак не связана с генсимом.

Hygienic macros are macros whose expansion is guaranteed not to cause the accidental capture of identifiers

Просто схема - это LISP-1, и без гигиены варианты с gensym нормально работать не будут.

anonymous
()
Ответ на: комментарий от anonymous

LISP-1 и LISP-2 никак не связаны с гигиеной. Варианты с генсим работать не будут нигде - ни в схеме ни в общелиспе (то есть в схеме они и без генсимов будут работать). Опровергнуть мои слова можно элементарно - всего лишь привести рабочий пример на общелиспе (то есть такой, который не будет падать, если кто-то переопределит внешний контекст).

anonymous
()
Ответ на: комментарий от anonymous

И, да, вопрос. Зачем в каждом макросе писать кучу генсимов, если можно делать это автоматически, гигиеной?

anonymous
()
Ответ на: комментарий от anonymous

Ты не то сравниваешь.

в любом случае будет меньше кода чем в схеме.

Вот вариант на общелиспе

Это низкоуровневая реализация.

anonymous
()
Ответ на: комментарий от anonymous

в любом случае будет меньше кода чем в схеме.

Ага. Ровно на вызов syntax-local-introduce. Я привел реализация на ракетке.

Это низкоуровневая реализация.

Это реализация вообще другого макроса.

anonymous
()
Ответ на: комментарий от anonymous

Это реализация вообще другого макроса.

никто разбираться в этом не будет. нечитаемый перл стайл.

а алгоритм примитивный. генерируем строчки вида «cadr» и списки вида `(cdr (car ,value)). первое - имя функции, второе - тело, value - аргумент.

anonymous
()
Ответ на: комментарий от anonymous

Зачем в каждом макросе писать кучу генсимов

в лисп-2 на порядок меньше, в лисп-1, наверное, никак. а как гигиена справляется с количеством вычислений форм с сайд эффектами?

anonymous
()
Ответ на: комментарий от anonymous
(define-syntax-rule (yoba x y) 
  (+ x y))

(let ([+ -])
  (yoba 1 1))

с гигиеной результат будет 2, без гигиены - 0.

Так ты испортил макрос. Торчащий наружу + - это такая же анафора, как и it. Макрос означает «применить то, что в месте вызова называется сложением». А у тебя гигиенка эту анафору испортила.

anonymous
()
Ответ на: комментарий от anonymous
(defmacro aif (test-form then-form &optional else-form)
  (let ((itt (gensym)))
    `(let ((,itt ,test-form))
       (symbol-macrolet ((it ,itt))
	 (if ,itt ,then-form ,else-form)))))

(defmacro yoba (x)
  `(aif (+ ,x 1)
	it
	,x))

(aif 3
     (yoba it)
     0)

4

Problem, officer?

k_andy ★★★
()
Ответ на: комментарий от anonymous

никто разбираться в этом не будет. нечитаемый перл стайл.

Общелисп же.

anonymous
()
Ответ на: комментарий от anonymous

в лисп-2 на порядок меньше

В лисп-2 столько же, сколько и в лисп-1. Повторяю, лисп-1/2 с гигиеной никак абсолютно не связано.

а как гигиена справляется с количеством вычислений форм с сайд эффектами?

Никак. Какая связь между сайд-эффектами и гигиеной?

anonymous
()
Ответ на: комментарий от anonymous

Так ты испортил макрос.

Это если гигиены нет. Если есть - ничего не портится.

Торчащий наружу + - это такая же анафора, как и it. Макрос означает «применить то, что в месте вызова называется сложением».

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

anonymous
()
Ответ на: комментарий от k_andy

Problem, officer?

У тебя йоба неправильная. Надо (aif (+ x 1) x it), а не (aif (+ x 1) it x). И форма должна вернуть 3.

anonymous
()
Ответ на: комментарий от anonymous

Эта информация, в частности, используется в дебагере - когда выполняете код, то дебагер прыгает на исполняемое выражение и выделяет его.

Эта информация достаётся интроспекцией из окружения, механизм макросов тут не при чём.

Лексический контекст - это и есть биндинги (упрощенно говоря, есть некоторые ньюансы, но вам они непринципиальны)

Биндинги создаются в рантайме, макросы разворачиваются даже до компиляции. Соответственно, видны будут символы только до того момента, когда форма раскрываться начала. И, собственно, какое это имеет отношение к гигиене?

Ну потому что это информация из компайлтайма, точнее из первой фазы :)

Макросы раскрываются до непосредственно компиляции. Либо какой-то аспект при объяснении гигигены был упущен, либо таки биндинги к гигиене отношения не имеют :)

Благодаря этому можно сравнивать идентификаторы по их биндингу и в частности реализовать нормальный макростепер

Это всё интроспекция в рантайме.

То есть вообще, если экспандер видит несвязанную переменную, он дает ошибку «unbound variable».

Как он может видеть, если переменная забаундится в рантайме? Он может не интернить символ автоматом и ругаться, если декларация интернинга пропущена.

mv ★★★★★
()
Ответ на: комментарий от mv

Эта информация достаётся интроспекцией из окружения, механизм макросов тут не при чём.

Нет, она как раз связана с макросами. В окружении этой информации просто нет.

Биндинги создаются в рантайме

Нет, биндинги создаются в первой фазе (то есть во время экспанда, по сути).

Соответственно, видны будут символы только до того момента, когда форма раскрываться начала.

Именно по-этому нужно два прохода экспандера.

И, собственно, какое это имеет отношение к гигиене?

Прямое. Гигиена - это механизм для управления биндингами.

Макросы раскрываются до непосредственно компиляции.

Я уже упомянул, что никакого рантайма и компайлтайма нет вообще - есть фазы, которые вдобавок относительны. Биндинги 0 фазы устанавливаются во время первой фазы, в это же время происходит экспанд кода 0 фазы.

Это всё интроспекция в рантайме.

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

Как он может видеть, если переменная забаундится в рантайме?

Потому что переменные баундятся во время экспанда, очевидно.

Он может не интернить символ автоматом и ругаться, если декларация интернинга пропущена.

С интернингом символов тут нет никакой связи.

anonymous
()
Ответ на: комментарий от anonymous

Нет, она как раз связана с макросами. В окружении этой информации просто нет.

Соурс локейшн к макросам отношения не имеет.

Прямое. Гигиена - это механизм для управления биндингами.

Ты путаешь intern и bind. Intern создаёт символ, bind привязывает к нему значение.

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

Работа с окружением (интроспекция) - свойство рантайма. То, что окружение, доступное макросу при его раскрытии, не существует при нормальной работе скомпилированной программы - это третье дело, не имеющее абсолютно никакого отношения ни к гигиене, ни к макросам в принципе.

С интернингом символов тут нет никакой связи.

Выше уже приводили правильное определение гигиенических макросов: они не делают неконтроллируемый интерн. Это всё.

mv ★★★★★
()
Ответ на: комментарий от anonymous

Анонимус, посоветуй литературы по теме. В референсе Racket черт ногу сломит и не хватает примеров.

anonymous
()
Ответ на: комментарий от anonymous

А в нем многие вопросы вообще не раскрыты. Типа тех же фаз или вилл.

Гайд Racket + референс Racket.

anonymous
()
Ответ на: комментарий от mv

Соурс локейшн к макросам отношения не имеет.

Ну зачем вы говорите о том, чего не знаете? Именно за счет макросов работа с ним и происходит. Хорошо, мы поступим просто - покажите мне, как при помощи методов интроспекции узнать source location выражения.

Ты путаешь intern и bind. Intern создаёт символ, bind привязывает к нему значение.

Именно. Интерн вообще не важен - он ни к макросам ни к гигиене никакого отношения не имеет вообще. Все символы интернятся (и скорее всего это будет вообще во 2 фазе, то есть во время раскрытия тела определения макроса) А вот бинд происходит во время экспанда макровызовов.

Работа с окружением (интроспекция) - свойство рантайма.

Конечно же нет. Окружение определено статически, с ним работают макросы.

То, что окружение, доступное макросу при его раскрытии, не существует при нормальной работе скомпилированной программы - это третье дело, не имеющее абсолютно никакого отношения ни к гигиене, ни к макросам в принципе.

Еще раз, гигиена - это средство для контроля за биндингами. Она позволяет выбирать какие биндинги будут у символа, менять их и т.п.. То есь окружение вполне себе существует при раскрытии.

Выше уже приводили правильное определение гигиенических макросов: они не делают неконтроллируемый интерн. Это всё.

Конечно, нет. Гигиена никак не связана с интерном, совершенно никак. Гигиена управляет биндингами. Если мы говорим о простейшей гигиене (неуправляемой, как в р5рс), то гигиена делает ровно следующее - устанавливает биндинги для всех используемых в макросе символов на область определения макроса (если эти биндинги там есть, конечно же, отсюда следует что, они должны существовать во время экспанда, иначе гигиена не могла бы работать). Вы бы это, конечно, знали, если бы были в курсе что такое гигиена и работали хоть раз с гигиенической макросистемой.

Вообще бросайте привычку говорить о том, о чем не знаете совершенно ничего. Плохая привычка.

anonymous
()
Ответ на: комментарий от anonymous

Правильно тебе сказали - доки к racket. Собственно, это вообще лучшие доки какие видел, так что грех жаловаться (тот же жуткий гиперспек со своими сепульками и рядом не стоял). Можешь еще добавить статьи plt team, там часто более доступно раскрываются те самые фазы, особенности рантайма, и объясняется зачем нужна та или иная фишка, и как оно применяется на практике. Книжку по ракете они пишут, но еще не дописали. Ну и всегда можешь задать вопрос на маиллисте - ответ обычно быстрый и исчерпывающий.

anonymous
()
Ответ на: комментарий от anonymous

Ну зачем вы говорите о том, чего не знаете? Именно за счет макросов работа с ним и происходит.

Ну покажи механизм, как это происходит.

Хорошо, мы поступим просто - покажите мне, как при помощи методов интроспекции узнать source location выражения.

Если выражение анонимное, то никак. Привязанное к символу - функции binds-who, who-binds, calls-who, who-calls в Лиспворксе, например.

Гуйня имеет возможность подчёркивать места с ошибочками за счёт eval-hook и macroexpand-hook, а не из-за каких-то волшебных грибовмакросов.

Именно. Интерн вообще не важен - он ни к макросам ни к гигиене никакого отношения не имеет вообще. Все символы интернятся (и скорее всего это будет вообще во 2 фазе, то есть во время раскрытия тела определения макроса) А вот бинд происходит во время экспанда макровызовов.

Значение присваивается символу во время экспанда макроса? А-ха-ха. Мы точно под байндом (bind) одно и то же имеем в виду?

mv ★★★★★
()
Ответ на: комментарий от anonymous

Конечно же нет. Окружение определено статически, с ним работают макросы.

Настолько статически, что у defmacro и macroexpand это входной аргумент, вобщем-то?

mv ★★★★★
()
Ответ на: комментарий от mv

Настолько статически, что у defmacro и macroexpand это входной аргумент, вобщем-то?

Какой defmacro? Какой macroexpand? Мы о гигиеничесикх макросистемах говорим, при чем тут defmacro?

Забудьте про комомон лисп, он тут не при делах.

anonymous
()
Ответ на: комментарий от mv

Ну покажи механизм, как это происходит.

Так я выше уже показывал пример с макросом.

Если выражение анонимное, то никак.

Ясно, то есть в принципе никак, ведь 99% всех выражений - анонимные. Замечательно, чо. О том уж чтобы делать трейсинг выражения на протяжении экспанда и речи нет - если выражение ушло в макрос, то пизда вам пришла, его оригинальный source location уже никак и ниоткуда не достать. Именно по-этому в racket точно указывается место ошибки и позиция конкретного выражения а в общелиспе выблевыается простыня раскрытого кода.

Гуйня имеет возможность подчёркивать места с ошибочками за счёт eval-hook и macroexpand-hook, а не из-за каких-то волшебных грибовмакросов.

Ну вот мой старый пример:

(defmacro yoba (invalid-expr) invalid-expr)
(yoba (+ 1 "2"))
покажите как сделать так с вашими хуками, чтобы здесь мне ИДЕ указало место ошибки - выражение "(+ 1 «2»)", локация - 2 строка, 7 позиция. Чего уж проще, не так ли?

Значение присваивается символу во время экспанда макроса? А-ха-ха. Мы точно под байндом (bind) одно и то же имеем в виду?

байнд это не установление значения, а связывание идентификатора (да, может в коммон лисп по-другому, но ведь о коммон лиспе и не говорил никто). То есть (let ([x 1]) (display x)) - экспандер проходит, видит х в лете, добавляет его в лексический контекст. Потом видит х в display, смотрит в лексический контекст, видит что там есть этот х, проверяет не зашадовлен ли он, какие у него синтаксические метки (не обращайте внимание, это особенности реализации гигиены) и устанавливает в контексте х в display, что это точно вот именно тот х, который определен в let, а не какой-то другой. Соответственно если экспандер увидит х, а до этого его в лексическом контексте нет (то есть он не определен дефайном или летом), то будет эррор - unbound variable

anonymous
()
Ответ на: комментарий от anonymous

Какой defmacro? Какой macroexpand? Мы о гигиеничесикх макросистемах говорим, при чем тут defmacro?

Да механизм-то одинаковый. Различие принципиальное есть, но разговор про это различие как-то не складывается.

mv ★★★★★
()
Ответ на: комментарий от mv

Да механизм-то одинаковый.

механизм как раз принципиально разный и рантайм поддерживающий этот механизм принципиально разный :)

В чем разница я уже объяснил, но вы зачем-то начали «а в коммон лисп не так!». Ну конечно не так, никто и не говорил иного.

anonymous
()
Ответ на: комментарий от anonymous

Ясно, то есть в принципе никак, ведь 99% всех выражений - анонимные. Замечательно, чо. О том уж чтобы делать трейсинг выражения на протяжении экспанда и речи нет - если выражение ушло в макрос, то пизда вам пришла, его оригинальный source location уже никак и ниоткуда не достать.

Ну вот собрал sexp в рантайме и сунул его в compile. Или из stream считал. Какой source location у второй скобки в той форме? В общем случае у произвольной формы сорс локейшена нет. Если ваша ракета позволяет найти определение произвольного sexp'а за счёт source location'а, а не поиска по исходникам, то я на это хочу посмотреть. Т.е. вводишь в каком-нибудь инпуте, жмёшь капу - оп, нашли.

покажите как сделать так с вашими хуками, чтобы здесь мне ИДЕ указало место ошибки - выражение "(+ 1 «2»)", локация - 2 строка, 7 позиция. Чего уж проще, не так ли?

http://13-49-ru.blogspot.com/2010/07/cltl2-vs-ansi.html

байнд это не установление значения, а связывание идентификатора .. то будет эррор - unbound variable

У вас в ракете нет динамических экстентов? Связать символ в рантайме нельзя?

(let ([x 1]) (display x)) ... устанавливает в контексте х в display, что это точно вот именно тот х, который определен в let, а не какой-то другой

А какой в этом примере может быть другой x?

mv ★★★★★
()
Ответ на: комментарий от anonymous

механизм как раз принципиально разный и рантайм поддерживающий этот механизм принципиально разный :)

Да всё так же. Если отбросить макросы, то движок языка будет одинаковым для lisp-1 и lisp-2. Да и с макросами тоже отличий не будет особых.

mv ★★★★★
()
Ответ на: комментарий от mv

Ну вот собрал sexp в рантайме и сунул его в compile. Или из stream считал. Какой source location у второй скобки в той форме? В общем случае у произвольной формы сорс локейшена нет.

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

Если ваша ракета позволяет найти определение произвольного sexp'а за счёт source location'а

Не понял, что?

http://13-49-ru.blogspot.com/2010/07/cltl2-vs-ansi.html

Пример-то будет? Повторюсь, мне хотелось бы узнать «как сделать так с вашими хуками, чтобы здесь мне ИДЕ указало место ошибки - выражение »(+ 1 «2»)", локация - 2 строка, 7 позиция. ". Впонле конкретный пример, пример простой (двустрочник).

А какой в этом примере может быть другой x?

Ну да, стоит немного переписать:

(define x 1)
(define-syntax-rule (yoba i) (define x i))
(yoba 2)
(let ([x 3]) (yoba 4) x)
вот у нас тут все 4 икса и все разные. По умолчанию тот икс, к которому мы обратились в let, это будет х = 3, но при желании можно сделать так, что это будет любой другой из этих 4.

anonymous
()
Ответ на: комментарий от mv

Да всё так же. Если отбросить макросы, то движок языка будет одинаковым для lisp-1 и lisp-2.

А при чем тут лисп-1 и лисп-2? Об этом никто и не говорил, действителньо, никаких существенных отличий лисп-1 от лисп-2 нет. Это не отменяет того, что рантаймы общелиспа и ракетки устроены принципиально по-разному, взять хотя бы фазы и модули. А алгоритм экспанда вообще другой совершенно.

anonymous
()
Ответ на: комментарий от anonymous

У скобок соурса нет

Ну вы же только что утверждали, что есть у всего. А теперь соглашаетесь:

общем случае у произвольной формы соурса нет

Повторюсь, мне хотелось бы узнать «как сделать так с вашими хуками, чтобы здесь мне ИДЕ указало место ошибки - выражение »(+ 1 «2»)", локация - 2 строка, 7 позиция. ".

В общем случае, никак, т.к. в общелиспе все токены в location-обёртку не заворачиваются. Степпер в лиспворксе текущую форму выделяет.

вот у нас тут все 4 икса и все разные. По умолчанию тот икс, к которому мы обратились в let, это будет х = 3, но при желании можно сделать так, что это будет любой другой из этих 4.

А чего у вас дефайн делает в случае уже забинденного символа?

Кстати, «define: not allowed in an expression context».

mv ★★★★★
()
Ответ на: комментарий от mv

Ну вы же только что утверждали, что есть у всего.

У выражений. Скобка - не выражение :)

А теперь соглашаетесь:

Он есть у всего, другое дело что он может быть определен плохо или некорректно. Однако, это бывает редко. Лучше пусть он будет определен в 99% случаев, чем в 1%.

В общем случае, никак, т.к. в общелиспе все токены в location-обёртку не заворачиваются.

Ну так да - я об этом и говорил, в общелиспе в обертку не заворачиваются, по-этому вместо нормального сообщения об ошибке выводится кривая простыня. В этом (корректном выводе сообщений об ошибках, удобстве отладки и т.п.) и состоит преимущество такого «заворачивания».

Степпер в лиспворксе текущую форму выделяет.

Только степпер? А как же просто исполнение программы? Ну и ладно - покажите как это происходит в степпере лиспворкса. Пример я дал, пример простой, в чем проблема-то?

А чего у вас дефайн делает в случае уже забинденного символа?

Если в топлевеле то дефайн будет переопределен. Если module/internal definition context, то:

(define x 1)
(define x 2)
будет ошибка, а так:
(define x 1)
(let ([x 2]) (define x 3) x)
все будет хорошо. то есть можно шадовить.

Кстати, «define: not allowed in an expression context».

Это в expression, а контекст внутри let'a - internal definition context, а не expression. Ну и не только внутри let'a, а внутри всех внутренних бегинов де-факто т.к. они сплайсятся во время partial-прохода экспандера.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.