LINUX.ORG.RU

Макросы + история успеха

 , , ,


2

3

Комрады. Сабж собственно - чем макросы racket лучше/хуже макросов cl и наоборот?

Второе - где, какой диалект и для чего (лиспа) вы применяете?

Всем спасибо.

З.Ы.: интерес к этому так как начали писать с коллегами большую система на racket. Стало интересно. Делаем just for fun

Основная разница в том, что в CL макросы не гигиеничные, а в Scheme (в том числе и в Racket) — гигиеничные. Лучше или хуже это уж каждый сам решает.

Использую Gerbil (разной степени сложности и упоротости проекты, от DSL для трейдинга до легкой очереди сообщений)

xerx ()
Ответ на: комментарий от silver-bullet-bfg

Гигиеничность гарантирует, что кишки макроса не выпадут в раскрываемый код.

Без неё получается так:

(defmacro fwrite (stream x)
  `(aif ,stream (format it "~a" ,x) nil))

(aif (get-data) (fwrite t it))

Упс. Вместо результата get-data напечаталось t.

monk ★★★★★ ()

чем макросы racket лучше/хуже макросов cl и наоборот

Любой макрос CL можно переписать в виде макроса Racket. Наоборот - не любой.

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

monk ★★★★★ ()

Вообще основное отличие Racket от CL – модульность. В Racket с чужим модулем можно сделать только то, что разрешил автор модуля. В CL можно сделать что угодно. Какой вариант лучше — существуют разные мнения.

так как начали писать с коллегами большую система на racket. Стало интересно. Делаем just for fun

Если система открытая, могу присоединиться.

monk ★★★★★ ()
Ответ на: комментарий от no-such-file

Попробуй изобразить на CL макрос типа aif, который можно было бы использовать в других макросах.

(define-syntax (aif x)
  (syntax-case x ()
    ((aif cond then else)
     (with-syntax ((it (datum->syntax x 'it)))
       (syntax
        (let ((it cond))
          (if it then else)))))))

(define-syntax-rule (fwrite str x)
  (aif str (fprintf it "~a" x) #f))
monk ★★★★★ ()
Ответ на: комментарий от monk

Любой макрос CL можно переписать в виде макроса Racket. Наоборот - не любой.

Как раз наоборот. При должном устремлении можно переизобрести и гигиеничную хрень, и остальное (но это никому не нужно, т.к. проблема которую решает гигиена высосана из пальца).

А вот конструкции с eval-when, и прочим подобным, на racket и не только в ней, изобрести, ессно, нельзя.

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

который можно было бы использовать в других макросах

Ок, первая наивная попытка

(defmacro aif (test then &optional else)
  (let ((it (gensym)))
    `(let ((,it ,test))
       (if ,it ,(subst it 'it then) ,(subst it 'it else)))))

(defmacro fwrite (stream x)
  `(aif ,stream (format it "~a" ,x) nil))

(aif (+ 42 105) (fwrite t it))

> 147
> NIL
no-such-file ★★★★★ ()
Ответ на: комментарий от Virtuos86

типичные лишперы

Всё самое лучшее в мире делается for fun. Как только начинается сурьозное сдвигание бровей и гордое надувание щёк, то сразу сбегаются индусы и прочие адепты процессов, и проект превращается в мёртвое амно.

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

Чем?

Т.к. с седой бородой уже, то имею право заявить… Вобщем, чем меньше тебя инструмент ограничивает, тем он гибче. Баги ты всё равно не будешь в продакшен шлёпать, если сам организован и понимаешь, что делаешь, а вот ограничения языка или окружения всегда сильно мешают.

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

Багов от самого общелиспа или по природе языка в продакшене не помню даже. У нас хорошая валидация была, лисповые баги через неё не проходили. Сишные и vhdl’ные - да, бывало.

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

Ничто так не эфемерно, как энтузиазм. Только что есть, и уже нету. Потеря мотивации в подобного рода проектах видится мне куда большей угрозой, чем ограниченность ракетки, которой стращает ТС’а Лавсан. Вот если бы имелся меркантильный интерес.

Virtuos86 ★★★★★ ()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от monk

Тогда почему в CL до сих пор нет call/cc?

Потому что стандарт с момента утверждения больше не изменялся?

Кроме того, с точки зрения исполнения кода на железе continuation - это очень плохая идея.

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

Потому что стандарт с момента утверждения больше не изменялся?

Так потоки и слабые ссылки добавили. Их тоже в стандарте нет.

Кроме того, с точки зрения исполнения кода на железе continuation - это очень плохая идея.

Даже в Си longjmp есть.

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

Так потоки и слабые ссылки добавили. Их тоже в стандарте нет.

call/cc не включили намеренно.

http://www.nhplace.com/kent/PFAQ/unwind-protect-vs-continuations-original.html

Даже в Си longjmp есть.

setjmp/longjmp это escape continuations, это как раз то что в CL.

(defun call/ec (f)
  (block exit
    (funcall f (lambda (&rest values)
                 (return-from exit (values-list values))))))
lovesan ★★ ()
Ответ на: комментарий от lovesan

setjmp/longjmp это escape continuations, это как раз то что в CL.

Через call/ec такое не сделать:

#include <stdio.h>
#include <setjmp.h>

jmp_buf ebuf;
void f2(void);

int main(void)
{
  int n=1;
  setjmp(ebuf);
  if (n < 10) {
    n++;
    f2(n);
    printf ("this will not be printed");
  }
  return 0;
}

void f2(int n)
{
  printf("%d\n", n);
  longjmp(ebuf, 1);
}
monk ★★★★★ ()
Ответ на: комментарий от korvin_

Очевидно ж

Ни разу не очевидно, т.к. тогда it не будет анафорой и это ничем не отличается от просто (if t '(got it)).

PS: если нужно такое поведение не вижу проблемы обойти дерево и заменять только там где нет quote, но мне лениво.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от no-such-file

т.к. тогда it не будет анафорой

ОК

(aif (+ 2 2) `(it is ,it) nil)

Должно быть ’(it is 4). Потому что смысл анафоры в том, что внутри формы переменная it имеет заданное значение, а не в текстовой подстановке.

PS: если нужно такое поведение не вижу проблемы обойти дерево и заменять только там где нет quote, но мне лениво.

Тоже не сработает. Контрпример в этом сообщении. И надо ещё учитывать, что внутри aif могут быть макросы, которые раскрываются в (quote …).

Создание нормальных макросов на CL по сложности сравнимо с разбором XML регулярными выражениями.

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

Я детали буста не смотрел, но если они там реально копируют весь стек и в куче его выделяют, плюс регистры, плюс остальное(всякое в C++ рантайме), то это по крайней мере тупо, т.к. представляет из себя натурально полноценный context switch обычной ОС, да к тому же еще и сделанный через задницу, и естественно тормозящий.

Ну и использование в коде выглядит невероятно вырвиглазно и отвратительно.

lovesan ★★ ()
Последнее исправление: lovesan (всего исправлений: 1)
Ответ на: комментарий от monk

Должно быть

Кому должно? С моей колокольни вполне логично, что it заменяется на актуальный символ всегда. Это гарантирует, что it будет всегда тем, чем был в макросе, а результат (it is 4) это нонсенс, т.к. it вообще-то в этом контексте уже не определён.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от Virtuos86

Он не простой как топор(это Си такой, скорее), а тупой как полено.

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

И проблема не в его существовании per se(для обучения младших школьников программированию он может и туда-сюда еще), а в том что люди на нем пытаются писать крупный софт.

Вот цитата Страуструпа в тему; хоть и не люблю его обычно, но тут он прав:

The idea of programming as a semiskilled task, practiced by people with a few months' training, is dangerous. We wouldn't tolerate plumbers or accountants that poorly educated. We don't have as an aim that architecture (of buildings) and engineering (of bridges and trains) should become more accessible to people with progressively less training. Indeed, one serious problem is that currently, too many software developers are undereducated and undertrained. Obviously, we don't want our tools--including our programming languages--to be more complex than necessary. But one aim should be to make tools that will serve skilled professionals--not to lower the level of expressiveness to serve people who can hardly understand the problems, let alone express solutions. We can and do build tools that make simple tasks simple for more people, but let's not let most people loose on the infrastructure of our technical civilization or force the professionals to use only tools designed for amateurs.
lovesan ★★ ()
Ответ на: комментарий от no-such-file

Кому должно?

Определению, данным автором (Полом Грымом в On Lisp).

An anaphor, it turns out, is a lot like a captured symbol. We can use anaphora in programs by designating certain symbols to serve as pronouns, and then writing macros intentionally to capture these symbols. In the new version of if, the symbol ``it'' is the one we want to capture.

а результат (it is 4) это нонсенс

Не (it is 4), а ’(it is 4). Это список из двух символов и числа. Символ определён всегда.

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

Я тут чуть-чуть подумал, и понял что мой наивный вариант действительно наивный и не работает, но не потому что «должно быть» а именно из-за «внутри aif могут быть макросы, которые раскрываются». Действительно нужно про каждую форму знать, раскрывается она или нет и несёт ли it внутри какой-то специальный смысл.

Но интересно, а в ракетке, например в (loop ... (collect it)) или чём-то подобном оно нормально работает?

Символ определён всегда.

Абстрактный символ нужно и указывать абстрактно, а не как анафору

(aif (+ 2 2) `(,(intern "IT") is ,it))
> (IT IS 4)

symbol «it» is the one we want to capture

Вот именно, мы его capture и используем специальным образом. Нельзя рассчитывать внутри такого макроса, что it будет вести себя как обычный символ.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 3)
Ответ на: комментарий от no-such-file

Абстрактный символ нужно и указывать абстрактно, а не как анафору

В aif от Поля Грэма и нормальный вариант работает.

Но интересно, а в ракетке, например в (loop … (collect it)) или чём-то подобном оно нормально работает?

Разумеется. Также как (let ((it …)) (….)) в CL.

monk ★★★★★ ()

Вообще проблема макросов схемы, racket итп - она в чем?

В том, что это макросы syntax->syntax а не sexpr->sexpr.

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

Макросы CL, же, в свою очередь, не ограничивают пользователя базовым языком, и позволяют писать свои DSL разных сортов, расцветок и размеров, бесшовно интегрируя это в язык(потому что языка на самом деле нет, а есть метаязыковая виртуальная машина. Ом. Но это отдельный вопрос). Потому что все что у нас есть на входе - это S-выражения, а не какое-то там AST(зачем на AST базового языка если мы пишем надстройку над ним? Незачем, мы не в его терминах уже оперируем).

lovesan ★★ ()
Ответ на: комментарий от no-such-file

Ни разу не очевидно, т.к. тогда it не будет анафорой

Абсолютно очевидно, т.к. quote и it здесь просто не вычисленный символ. Твоя же подстановка совсем не учитывает контекста.

и это ничем не отличается от просто (if t '(got it)).

В данном случае ничем и не должно, quote же почти как строковый литерал, только S-exp. Внутри него только reader-макры работают, но aif же не reader-макра.

korvin_ ★★★★★ ()