LINUX.ORG.RU

Lisp, Haskell, Smalltalk, Forth... что дальше?


1

0

Навеяно предыдущей темой.

Последнее время совершенно отчетливо прослеживается, как маргинальные языки передают друг другу олимпийский факел, в смысле их популярности на ЛОРе.

Факел был когда-то зажжен незабвенным Проффессором Луговскером, и достался он лиспу. Прошло несколько лет, и теперь даже самый распоследний нубас на ЛОРе расскажет вам про REPL, метапрограммирование, квазиквотацию, eval, Slime и про жаба-monkey-кодеров. Лисп стал популярен на ЛОРе, и утратил позиции «элитного» языка, дискутировать о котором могли единицы.

Ниша долго не пустовала. Некоторое время факел находился у Haskell, а последние месяцы его гордо несет Smalltalk (я сужу исключительно по количеству новостей и дискуссий о нем). Но теперь завзятые маргинальщики начинают интересоваться Forth'ом, из чего я делаю вывод о том, что факел Smalltalk'а начал коптить, в силу его популяризации на ЛОРе.

Предлагаю коллективно поразмыслить над тем, какой язык мог бы принять эстафету у Форта. Из маргинальных неэзотерических языков осталось не так уж и много. Clean? Pure? Factor?

★★

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

> так вот, если какой-то «специализированый» язык умеет то, что невозможно или некрасиво реализуется на якобы языке общего назначения Х, то это означает, что Х — не есть язык общего назначения

На Си очень некрасиво реализуется все то, что легко и красиво умеет Пролог, или хуже того, Yacc. Но Си при этом - язык самого что ни на есть общего назначения.

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

> DSL должны умереть, embedded DSL наше все

Зачем ембеддить тот же yacc? Чтоб очередной уродливый Spirit получился? Не надо.

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

>невозможно или некрасиво реализуется на якобы языке общего назначения

Проблема же не в «возможно» (тут они почти все одинаковы), и не в «красиво» (всегда можно добавить сахару), а в том, что в «общем» случае автору ещё предстоит сделать и то и другое, а разработчики «спец"языка *уже* это сделали.

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

> Но Си при этом - язык самого что ни на есть общего назначения.

бугага

си — это язык для ковыряния байтов в плоской сегментированной модели памяти, это даже в введнии его стандарта (или с++, не помню) пишут

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

> Зачем ембеддить тот же yacc? Чтоб очередной уродливый Spirit получился? Не надо.

Уродство Spirit-а опять означает то, что с++ не есть ЯОН.

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

> Проблема же не в «возможно» (тут они почти все одинаковы), и не в «красиво» (всегда можно добавить сахару), а в том, что в «общем» случае автору ещё предстоит сделать и то и другое, а разработчики «спец"языка *уже* это сделали.

Ага, сделали, но если ты захочешь сам что-то чуть изменить в этом DSL — можешь заранее повеситься. В то время как DSL, реализованном даже на несовершенных плюсовых шаблонах что-то до/пере-делать вполне реально.

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

> тогда, конечно, появляется идея type inference и/или аннотаций типа для готового кода, но дополнительно жизнь осложняет то, что эти библиотеки могут быть написаны не только на самом языке, а допустим на си, как в случае РНР; думаю, у лиспа тоже порядком библиотек, юзающих FFI и значит си, а то и с++

Есть и такие. Но cffi довольно жестко относится к с-шным библиотекам в этом смысле.

2. очень интересно, как ты собираешься тайпчекать макросы

А в этом смысле макросы почти ничем не отличаются от функций.

хотелось бы тайпчекнуть макрос так, что бы быть уверенным, что он раскроется в правильный код независимо от тех компайл-тайм переменных, от которых он зависит (ну там констант или типов)

Макросы очень редко используют внешние переменные. Плохой тон. Но даже если используют в чем проблема?

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

как обеспечить обязательный тайп-чек после выполнения произвольного кода в макросе? есть ли в CL поддержка этого момента?

Слова по отдельности понимаю. предложение из них нет.

Макрос не выполняет произвольный код и даже в него не раскрывается.

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

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

> кстати, в диалекте схемы, который называется racket, че-то сделали на эту тему, но х.з. как у них с этими проблемами и что там в CL, т.к. макросы в нем не те

Я честно читал главу о контрактах но особых отличий от CL не нашел. Typed racket видимо большей частью перили в контракты. Проверка типов по тексту по-моему динамическая т.е. проверили аргументы, проверили что на выходе.

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

> макросы нужны немного в иной форме — в основном на «чтение AST», создание же AST делать, вероятно, другим методом

А пояснить с примерами?

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

>>> DSL должны умереть, embedded DSL наше все

>> Это была шутка?

> нет, я серьезно

Я создавал и то, и другое. Нельзя все свести к eDSL, например, компиляцию DSL в какой-то исполняемый код, как было в моем случае (хотя в f# есть quotations, в лиспе - макросы, но это такой overkill по сравнению с DSL, если предусматривать все случаи использования). У меня производительность откомпилированного DSL и eDSL отличается на два порядка на общей задаче. Одно это перевешивает все минусы DSL. Задача вычислительная.

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

>вообще-то, в моем посте речь шла всего лишь о способах создать статическую типизицию поверх динамической;

макросы нужны немного в иной форме — в основном на «чтение AST», создание же AST делать, вероятно, другим методом

это не так.

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

> это не так.

сначала давай все-таки разберемся со статической типизацией поверх динамической; я перечислил часть проблем (1, 2А, 2В)

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

возможно надо различать

1. «синтаксис языка, базирующийся на динамической типизации» и

2. «семантика языка, базирующаяся на динамической типизации»

можно рассмотреть например язык, который получается из явы с помощью вот таких *чисто* синтаксических изменений:

все присваивания в объявлених переменных пишем с ":="; убираем слово Object из всех сигнатур функций и определений классов

было: Object f(Object o) { int x=1; Object y; Object z=t; z=x; return z; }

стало: f(o) { int x:=1; y; z:=t; z=x; return z; }

в получившимся языке имеем п.1 но не п.2 — этот язык останется явой с ее статической типизацией

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

> У меня производительность откомпилированного DSL и eDSL отличается на два порядка на общей задаче.

и почему ты считаешь, что это недостаток eDSL вообще, а не языка-контейнера для eDSL или конкретной реализации?

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

макросы нужны немного в иной форме — в основном на «чтение AST», создание же AST делать, вероятно, другим методом

А пояснить с примерами?

хороший вопрос

допустим, нам надо реализовать switch, подобный сишному, но для строк:

char* x = get_x();
switch(x)
{
  case "char"    : return 1;
  case "int"     : return 2;
  case "long"    : return 3;
  case "short"   : return 4;
  case "unsigned": return 5;
  default: return 0;
};

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

тут просится либо лисп-лайк макрос, либо че-то поумнее — накатаю как-нить статейку и запощу ссылку на ЛОРе

и кстати, как присутсвующие относятся к blogspot.com? имеют ли там бложики? или хотя бы гугловые аккаунты?

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

> А почему именно он?

мне чаще всего там встречаются интересные бложики по программированию, затем в LJ

предложи другой вариант, мне интересно

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

лохспот - нормально. Главное, чтоб можно было анонимно и с опенид постить.


возможно, что для константных строк из него надо делать не тупую

линейную цепочку if-ов, а что-то типа таблицы переходов по первой


букве (или даже части бит первой буквы) и допроверке там



Вот такой вопрос: это всегда будет быстрее? И можно пример такой
таблицы переходов, пожалуйста.

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

можно там анонимно и с опенид постить

тут даже видимо и без таблицы переходов можно, просто с таблицей значений; а то что быстрее — так навскидку, а вообще посчитать надо

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

Ну покажи плиз код, который должен макрос генерить

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

> Вот такой вопрос: это всегда будет быстрее? И можно пример такой таблицы переходов, пожалуйста.

man flex

anonymous
()

>Из маргинальных неэзотерических языков осталось не так уж и много

Всё кладбище разрыли :)

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

>> У меня производительность откомпилированного DSL и eDSL отличается на два порядка на общей задаче.

> и почему ты считаешь, что это недостаток eDSL вообще, а не языка-контейнера для eDSL или конкретной реализации?

Не так. В данном случае я считаю, что это достоинство DSL. Совсем другой расклад.

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

> как присутсвующие относятся к blogspot.com? имеют ли там бложики? или хотя бы гугловые аккаунты?

Корявый редактор. Копи-паста работает плохо и почему-то на разных браузерах по-разному, причем лучшего всего дружит с Оперой. Кажется, нет аттача файлов, что иногда было бы полезно. Сейчас я бы посмотрел в сторону LJ - много fp-народу тусуется там.

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

>> DSL должны умереть, embedded DSL наше все

Зачем ембеддить тот же yacc? Чтоб очередной уродливый Spirit получился? Не надо.

Это просто С++ такой, что трудно сделать красиво. Тот же parsec в хаскеле - одно удовольствие.

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

>У меня производительность откомпилированного DSL и eDSL отличается на два порядка на общей задаче.

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

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

> Ну, для того же лиспа, например, это не должно быть проблемой.

Проблема в том, что мой eDSL получился гораздо шире и гибче, чем DSL. Соответственно, «компилировать» eDSL просто замучаешься. И мне кажется, что это как бы свойство eDSL быть «шире и гибче».

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

[quote] допустим, нам надо реализовать switch, подобный сишному, но для строк:

[code] char* x = get_x(); switch(x) { case «char» : return 1; case «int» : return 2; case «long» : return 3; case «short» : return 4; case «unsigned»: return 5; default: return 0; }; [/code]

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

тут просится либо лисп-лайк макрос, либо че-то поумнее — накатаю как-нить статейку и запощу ссылку на ЛОРе [/quote]

Таблица переходов для константных строк? И эти люди рассказывают о том что лисп якобы неправильный :) Первый же пример макроса - выглядет костылем странной реализации вместо нормальных символов.

[quote] и кстати, как присутсвующие относятся к blogspot.com? имеют ли там бложики? или хотя бы гугловые аккаунты? [/quote]

blogspot на мой вкус стремно комментировать. Гугдовцы мало того что запихали в iFrame так еще и js впихали что не во везде работает. Это конечно лично-наболевшее, но гугл-продукты я из-за такого подхода не люблю (ну кроме поиска).

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

Рассказал бы хоть о задачи, а то о сферических DSL-ях рассужать как то беспредметно.

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

> Таблица переходов для константных строк? И эти люди рассказывают о том что лисп якобы неправильный :) Первый же пример макроса - выглядет костылем странной реализации вместо нормальных символов.

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

лисп-лайк символы тебе не помогут, если get_x получает свой char* откуда-то извне, например из (mmap-нутого) файла

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

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

switch на константных строках (или у вас COND на константных строках) это как раз пример более хитрого макроса — он должен обработать свои часть своих аргументов (а именно константные строки) не просто eval-ом

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

допустим, нам надо реализовать switch, подобный сишному, но для строк

«Параметрически-полиморфный» макрос case? Что может быть проще:

(defmacro my-case (object &rest cases)
 `(cond ,@(mapcar #'(lambda (case)
		      `((equal ,(first case) ,object) ,@(rest case)))
		  cases)))

А если хочется более умного поведения, то для объекта `object' (первый элемент входного AST) можно получать предикат сравнения для объектов данного типа:

(defun get-equaler-p (object)
  (typecase object
    (number    '=)
    (character 'char=)
    (string    'string=)
    (t         'equal)))

(defmacro my-case (object &rest cases)
 `(cond ,@(mapcar #'(lambda (case)
		      `((,(get-equaler-p object) ,(first case) ,object) ,@(rest case)))
		  cases)))

возможно, что для константных строк из него надо делать не тупую линейную цепочку if-ов,

а что-то типа таблицы переходов по первой букве (или даже части бит первой буквы) и допроверке там

И в случае константных строк, и в случае переменной - достаточно одного cond, который суть макрос-синоним для цепочек if-ов.

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

Antlr все равно гораздо большее удовольствие чем все эти кривоватые и тормозные парсеки. DSL всегда лучше чем eDSL.

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

write-only. Пёрл отдыхает рядом с таким кодом.

Интересно, а в чём дело? Положи перед дитём листок с python/ruby/c кодом (нужное подчеркнуть) тоже будет агу-онли. Там правил-то всего несколько - но если их не знать, то конечно нифига будет непонятно :)

А если так:

(defmacro my-case (object &rest cases) 
 `(cond ,@(mapcar #'(lambda (case) 
            `((equal ,(first case) ,object) ,@(rest case))) 
        cases))) 

macro my-case object cases ...
  quote
    "cond"
      intern eval
             map lambda case
                   quote
                     "equal" eval (first case) eval object 
                     intern eval (rest case)
             cases

макрос называется my-case от аргументов object и cases
  берём как есть
    "cond" (это вложенные if, короче)
      вклеиваем результат вычисления
        map лямбду от case
          опять берём как есть
            "equal" вычисляем (first case) вычисляем object сюда
            вычисляем и вклеиваем (rest case)
        cases (это cases map-иться)

Нда, так вообще ничего не понятно. Но всё равно, вы меня задели :) «Я па руски не говорить, врайт-онли».

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

>Antlr все равно гораздо большее удовольствие чем все эти кривоватые и тормозные парсеки. DSL всегда лучше чем eDSL.

1) парсек быстрый.

2) используя eDSL, тебе очень легко доступна вся мощь собственно основного языка. В данном случае хаскеля.

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

> «Параметрически-полиморфный» макрос case?

неееееет

в общем, раз уже 2 человека поняли меня неправильно, стоит прекратить разговор на эту тему, и продолжить его в виде «подробная статья и затем только обсуждение»

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

>(defun get-equaler-p (object) ...

(defmacro my-case (object &rest cases) ... `((,(get-equaler-p object)...



Ты это хоть опробовал? Вывод macro-expand покажи. При раскрытии твоей макры my-case object не более чем символ, и что тебе должна вернуть get-equaler-p? Ишь, быстрый какой, тремя строками типизировал всё CL-ное «макроисчисление»...

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

>в общем, раз уже 2 человека поняли меня неправильно...

есть подозрение, что посимвольно-пошаговое сравнение строк может дать выигрыш только в голом си, а во всяких там jvm-like языках и лиспах функция сравнения строк (весьма вероятно «нативная») может оказаться быстрее бороды с «извлечением» символов и сравнения оных... Не? Если только у тебя case не на пару сотен позиций...

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

наверное он хотел написать примерно так:

(defgeneric get-equaler (x)
  (:documentation "Returns equality predicate for class of argument."))

(defmacro defequaler (class-name func)
  `(defmethod get-equaler ((x ,class-name)) #',func))

(defequaler t         equal)
(defequaler number    =)
(defequaler character char=)
(defequaler string    string=)
(defequaler symbol    eql)


(defmacro my-case (object &body cases)
  (labels ((make-eq-expression (case)
             `(funcall ,(get-equaler case) ',case ,object))
           (transform-my-case (case body)
             (cond ((case case ((t otherwise) t))
                    (cons t body))
                   ((atom case)
                    (cons (make-eq-expression case) body))
                   (t `((or ,@(mapcar #'make-eq-expression case)) ,@body)))))
    `(cond ,@(loop :for (case . body) :in cases
                   :collect (transform-my-case case body)))))

но почему-то не написал =)

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

get-equaler-p работает как спецификатор только для (and atom (not symbol)), в остальном берётся общий #'equal (там в typecase последний тип какой?).

Но это как бы очевидно - как его для символов заставить работать в рантайме (уже после раскрытия). Можете поупражняться :)

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

>> write-only. Пёрл отдыхает рядом с таким кодом.

Нормальный, читабельный, код. Просто ты CL не знаешь.

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

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

Хотя, может и не такой плохой :) Но методы тут не к месту - нужно использовать typecase для получения подобной информации о типах, а не диспетчеризацию. По крайней мере так уж CL устроен - CLOS это мета-язык над базовым CL-без-CLOS, типы и классы разделены, а для реализации базовых специальных форм (case) вы не можете себе позволить тянуть CLOS.

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

вы не можете себе позволить тянуть CLOS.

Блин, но если всё таки позволите себе - то будет здорово :) Просто пока так не делают ещё.

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