LINUX.ORG.RU
ФорумTalks

Джон Кармак - готов был бы заплатить за опыт с Common Lisp

 , , , ,


3

3

«Significant Lisp experience is one of those things I would pay money to have, but can't ever find the time to get.»
---
«Знаменательный опыт с Lisp - одна из тех вещей за которые я был бы готов заплатить, но никак не могу найти время, что бы получить его»

Пруф: https://twitter.com/ID_AA_Carmack/status/299577802385154048
---------------------------

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

Перемещено tazhate из development



Последнее исправление: CYB3R (всего исправлений: 3)

Я думал он хотит написать fps на cl. Я, кстати, написал простой воксельный raytracer на cl. Он тормознутый, так как я идиот и не умею программировать. Но мне интересно, насколько бы быстрее он был, если бы всё то же самое было написано на C (в его же сишном стиле). Но то, что было бы куда больше кода, это я не сомневаюсь

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

давай сюда свой raytracer - тебе расскажут что и как надо было делать )))

yyk ★★★★★
()

В переносном же смысле. А если бы он сказал «убил бы за знание Лиспа», лисперы бы начали обсуждать, кого принести в жертву?

anonymous
()

Он вообще как-то сказал, что подумывал о том, чтобы всё переписать на Хаскеле.

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

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

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

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

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

потыкай хаскель, он без скобочек.

А вообще, схема довольно проста и скобочки там к месту.

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

Нету такого языка - «Lisp». Зато есть такое семейство языков. Если человек говорит «лисп» - то это значит любой лисп. То есть любой язык из семейства. Если он имеет в виду какой-то конкретный лисп - пусть уточняет.

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

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

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

А вот здесь http://cyclone.thelanguage.org/, написано: «Cyclone is a dialect of C». Так что C тоже нет, а есть «семейство» из ANSI C, C99, Cyclone, .... У Java такие же самоназванные диалекты: Guava и Godiva, J#, J++. У С++ есть Borland C++ Builder и .Net C++.

Так что или их всех тоже не существует и Oracle Java имеет не больше прав на слово Java, чем J# (по аналогии с Common Lisp и Scheme). Или, всё-таки, не надо путать оригинальный язык (C, C++, Oracle Java, Common Lisp) и диалекты (Cyclone, Borland C++ Builder, J# и Scheme).

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

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

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

den73 ★★★★★
()

forth

Странно, что про него никто не написал.

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

Ага, значит мне просто самый пик запомнился, в каком-то лиспосраче ты весьма эмоционально спорил, со стороны выглядело как развенчаторство лиспомифов. Хорошо, что разъяснил.

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

Или, всё-таки, не надо путать оригинальный язык (C, C++, Oracle Java, Common Lisp) и диалекты (Cyclone, Borland C++ Builder, J# и Scheme).

То есть, Common Lisp — тоже не Лисп? Да ты гений!

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

Читай внимательней.

Common Lisp настолько же является лиспом, насколько Oracle Java является явой.

В отличие от всяких J# и Scheme

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

Лиспомифы, безусловно, существуют. Например, разбирался пример с вычислениями, где SBCL слил по той объективной причине, что fixnum в нём имеет разрядность меньше, чем разрядность платформы. Однако это - частность и она не перечёркивает достоинств лиспа. Лиспомифы надо развенчивать, если есть желание, чтобы лисп развивался дальше.

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

хотя, не исключено, что у меня могло быть настроение о том, что лисп - это плохо вообще. На сегодня я считаю, что CL как платформа близок к идеалу, но как ЯП - далёк от него. Вопрос решается созданием другого языка на платформе CL.

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

Настроение так настроение, главное, теперь у меня одним заблуждением меньше.

С лиспом все ясно, хотя, признаться, нормальные dsl-и на нем я так и не осилил.

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

CL как платформа близок к идеалу

Интересное утверждение. У платформы CL есть несколько неустранимых недостатков:

1. Динамическая типизация. Соотвественно, ограничение по скорости.

2. GC, не позволяющий сохранять адреса в помяти. Опять ограничение на скорость (и на ручное управление памятью).

3. Всё вызовы функций виртуальны. В смысле, по символу, а не по адресу. => опять скорость.

Для CL 1-3 неустранимо, так как требуется языком. При реализации того же паскаля (или ещё лучше, хаскеля) поверх CL будет нехилое проседание производительности.

Поэтому «самым быстрым» лисп (и всё что угодно на его платформе) быть не может. А самым гибким он и так является (синтаксический сахар каждый себе досыпает по вкусу).

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

Ну я и читаю:

не надо путать оригинальный язык и диалекты

То есть, по твоему выходит, что Scheme — оригинальный язык, а CL — его диалект и, следовательно, совсем не лисп.

Значит, либо ты прав и CL не лисп, либо CL таки лисп, а ты — дурень.

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

Ну я и читаю:

не надо путать оригинальный язык и диалекты

Было написано:

не надо путать оригинальный язык (...Oracle Java, Common Lisp) и диалекты (... J# и Scheme).

Или ты настолько ненавидишь лисп, что не можешь даже читать внутри скобочек?

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

Динамическая типизация. Соотвественно, ограничение по скорости.

Тебе неплохо бы подучить матчасть всё-таки. Как правило, динамическая типизация устраняется с помощью type,ftype,the и optimize.

GC, не позволяющий сохранять адреса в помяти.

Да, такая проблема есть, отчасти она решается поколенческой сборкой мусора, которая используется во всех ведущих реализациях. С другой стороны, нет фрагментации памяти, а её выделение - операция быстрая. С третьей - можно работать с внешними объектами, поэтому если очень надо - то можно выделять память вручную. С четвёртой стороны - эта же проблема (насколько я могу себе помыслить) имеется в Java и .NET, что им не мешает. С шестой, dynamic-extent позволяет размещать объекты на стеке.

Всё вызовы функций виртуальны. В смысле, по символу, а не по адресу

Стандарт лиспа не требует виртуальных вызовов. Можно хранить сведения о cross-reference и это позволит полностью избавиться от виртуальных вызовов за счёт роста размера образа (видимо, на единицы-десятки процентов) и замедления компиляции, при сохранении возможности подмены функции. Не знаю, насколько это используется в реализациях (в Lispworks за 5 минут не смог привести примера такой оптимизации). Но, судя по результатам SBCL здесь, http://benchmarksgame.alioth.debian.org/u32/performance.php?test=pidigits#about, можно предположить, что всё не так плохо. На худой конец, есть inline.

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

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

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

С лиспом все ясно, хотя, признаться, нормальные dsl-и на нем > я так и не осилил.

Насколько я понимаю жизнь, в лиспе и не предполагаются «нормальные» dsl-и. Предполагаются «быстрогрязные». Для нормальных dsl-ей нужны развитые средства поиска ошибок компиляции, специфичных именно для этого DSL с указанием места ошибки, подсветка синтаксиса и т.п. Лично мне не попадался канонический пример такого DSL-я на CL, если кто-нибудь покажет - я буду рад взять свои слова назад. Быстрогрязные DSL-и имеют такой же (относительно низкий) степень комфорта для разработчика, не считая динамической природы и всего, что из этого вытекает.

Лучший DSL, к-рый я сам написал, фактически является «обычным» макропроцессорам с лексером текста, реализованным в среде лиспа. Механизм поиска ошибок у него частично написан с нуля, частично опирается на возможности среды (assert-ы и т.п.). Completion взят от лиспа и это в большой степени устраивает. Подсветки синтаксиса у меня до сих пор нет, но нет сил делать это одному (хотя вроде несложно, но некогда). Навигация по исходникам (M-.) построена на базе среды. Некоторые команды поддержки специфики предметной области написал сам, например, есть команда «показать список полей таблицы SQL».

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

Ты сейчас говоришь, что я был неправ когда не стал тебя гандонить за очевидную опечатку «внутри скобочек»? Ну ладно, постараюсь. Ты — тупая мразь! Иди улицы подметать, если не можешь написать одно предложение не перепутав местами два слова! А лучше — околей и сдохни, быдло!

Так сойдет?

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

1. Слишком сложен. Много конструкций там, где хватит и одной.

2. Непривычен для новичка - например, составной оператор называется progn.

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

В С реперные точки возникают из-за того, что есть разные виды скобок - {}, (), [], ->, . ; В лиспе реперных точек мало, потому что только один вид скобок. К тому же - множество тире вместо CamelCase приводит к заметному удлинению текста. Правда, религиозные лисперы этого не понимают, что меня не устаёт удивлять.

4. Скобок слишком много. В других языках приоритеты операций позволяют избавиться от части скобок. Если приоритеты выбраны удачно - то скобок становится намного меньше. Лисп безжалостен: число скобок равно числу структурных элементов.

5. Местами слишком многословен, например, вместо a.b нужно писать (slot-value a 'b) (хотя это мне удалось отчасти для себя поправить). Некоторые важные ключевые слова слишком длинны (например, multiple-value-bind).

6. Неудобно устроена система пакетов (хотя это мне удалось для себя поправить).

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

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

Предполагаются «быстрогрязные»

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

С другой стороны, те хелуводы, что в свое время понаделал, до сих пор служат мне исправно.

Ну и опыт, это да, опыт применения лиспа обогащает. Словно шоры снял.

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

Предполагаются «быстрогрязные», да, а под «нормальным»

Нет, вопрос не в сложности DSL, а именно в уровне предоставляемого сервиса. Как раз для простых DSL недостаток сервиса в CL будет ощущаться сильнее. Если делаются сложные DSL-и, то для них всё равно нужны специализированные средства диагностики и отладки. Например, для SQL нужно средство просмотра планов. Такое средство совершенно не связано со способностью компилятора показать место ошибки в исходном тексте с точностью до буквы.

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

До сервиса я тем более не добрался. Ну да ладно, вернусь к этому как-нибудь. Надеюсь.

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

Как правило, динамическая типизация устраняется с помощью type,ftype,the и optimize.

Хм, что мне написать для компиляции в

unsigned plus(unsigned x, unsigned y) { return x + y; }

?

(declare (type (integer 0 4294967295) x y) не помогает. Всё равно использет длинную арифметику.

Аналогично, не даст сделать массив структур, например. Только массив указателей или примитивных типов.

В общем, тэги+боксинг забороть в JVM вроде как проще.

Стандарт лиспа не требует виртуальных вызовов.

Он требует late binding. И в SBCL выглядит так

(defun test3 (x) (cons (test2 x) 1))
(disassemble 'test3)
...
;       3C:       8B05007E1D0C     MOV EAX, [#xC1D7E00]       ; #<FDEFINITION object for TEST2>
;       42:       B904000000       MOV ECX, 4
;       47:       892B             MOV [EBX], EBP
;       49:       8BEB             MOV EBP, EBX
;       4B:       FF5005           CALL DWORD PTR [EAX+5]
...

В C++ такой метод вызова применяется только для виртуальных методов, а в SBCL — для всех.

Можно хранить сведения о cross-reference...

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

http://benchmarksgame.alioth.debian.org/u32/performance.php?test=pidigits#about,

Ага. А PHP в этом тесте круче лиспа. Посмотри код, там первые 10 мест — сравнение эффективности FFI к gmp. А решение без FFI — 33 секунды протиа 26 у Java, 16 у Ruby и 3 у С/С++.

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

Да я и не спорю. Просто без лиспа 90% этих наворотов не надо. Или твой «язык на платформе CL» должен будет потянуть за собой почти всю семантику CL, или его выгодней делать на JVM/Net/LLVM.

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

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

(declare (type (integer 0 4294967295) x y)

Не знаю. Для начала, сумма двух таких чисел всегда является fixnum-ом в твоём SBCL?

В смысле, ты предлагаешь перекомпилировать все зависимые функции?

Не совсем. Проходить по машинному коду и править аргументы call/jmp, а это - не вся компиляция, а лишь один из её этапов. Кстати, это придётся делать не только при перекомпиляции, а ещё и при перемещении вызываемой функции сборщиком мусора. Так что данный механизм далеко не всегда приведёт к росту производительности.

Посмотри код, там первые 10 мест

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

В общем, тэги+боксинг забороть в JVM вроде как проще.

А там бигнумы есть или там переполнение даёт неверный результат сложения?

Просто без лиспа 90% этих наворотов не надо

Что именно не надо из того, что обсуждалось?

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

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

Вот в этом я с тобой и не согласен. Внутри любого Lisp-объекта всегда есть тэг типа. Поэтому fixnum всегда в несколько раз меньше, чем int. Избавиться от тэга можно только для чисел и букв и только в массивах.

Поэтому даже, если сумма гарантировано в int32, заставить SBCL вычислить через ассемблерный ADD всё равно не выйдет. Только если fixnum.

А там бигнумы есть или там переполнение даёт неверный результат сложения

Есть. Если напишешь BigInteger, будет длинная арифметика, если Integer — то нет, если int то будет целое, не являющееся объектом. Переполнение по желанию программиста. А на CL платформа такой свободы не даёт.

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

Что именно не надо из того, что обсуждалось?

Для паскаля не нужны тэги в объектах, не нужны виртуальные функции, для классического паскаля не нужен сборщик мусора. Поэтому Pascal-over-CL будет тормознее оригинального Pascal.

Для Java не нужны тэги в объектах, нужны нормальные числовые типы (int + int считающийся через bignum — очень грустно).

Я же говорю, что весь вопрос, что ты хочешь нарисовать поверх CL? Более-менее нормально можно сделать Ruby, Smalltalk, JS. С сильными тормозами будет любой язык с статической типизацией (Java,Pascal), семантика работы с указателями почти невозможна (точнее возможна поверх массивов, а значит не очень быстро).

Да, для перечисленных не нужен сигнальный протокол, который тяжелее, чем RTTI от C++ (а для try/except достаточно его).

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

Внутри любого Lisp-объекта всегда есть тэг типа.

Спорить не буду, но не стану и соглашаться. Во всяком случае, не вижу, как это следует из стандарта для:

- живущих на стеке объектов непосредственных типов в компилированных функциях

- элементов массивов непосредственных типов.

Если объект живёт в куче, то у него должен быть тег типа, иначе не получится реализовать точную сборку мусора. Можно, конечно, представить такой аномальный случай, как консервативная сборка мусора, но она пригодна только для частных случаев.

Если считать тег типа расплатой за точную сборку мусора - то цена представляется адекватной.

И расскажи мне, как может жить в JVM объект без тега типа на куче.

если сумма гарантировано в int32, заставить SBCL вычислить через ассемблерный ADD

Но я так и не понял, в твоём случае, является ли сумма двух чисел fixnum или нет, у меня нет SBCL под рукой - проверить. Если она не является fixnum, то SBCL поступил правильно.

А на CL платформа такой свободы не даёт.

Если брать стандарт, то, видимо, не даёт. Но в Lispworks, например, есть 32-разрядная арифметика, соответствующая int.

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

нужны нормальные числовые типы (int + int считающийся через bignum — очень грустно).

Ещё раз: внезапно выяснилось, что объект без тега типа может жить только на стеке или в массиве. Так что твой пример ничего не доказывает. По умолчанию я продолжаю считать, что unboxing возможен.

Для паскаля не нужны тэги в объектах, не нужны виртуальные >функции, для классического паскаля не нужен сборщик мусора. >Поэтому Pascal-over-CL будет тормознее оригинального Pascal.

Будет. Разве с этим кто-то спорит?

С сильными тормозами будет любой язык с статической типизацией

С сильными тормозами по отношению к JS или к оригинальному Pascal? Разные вещи.

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

живущих на стеке объектов непосредственных типов

Они, как правило даже не на стеке, а в регистрах живут.

элементов массивов непосредственных типов

Элемент массива не совсем объект. Причём для массива я уже говорил, что платформа не даёт сделать массив структур. struct {int x; int y} a[100]; в лиспе становится массивом указателей.

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

А как же JVM? И зачем «собирать» то, что не указатель: int32, структуры на стеке? В JVM у чисел нет тэга типа и на куче они не живут. Там только указатели.

Если она не является fixnum, то SBCL поступил правильно.

Не является, потому что fixnum меньше, чем int. Сумма двух 31-битных чисел тоже в fixnum не влазит. Поэтому ни один язык с базовым типом int поверх CL сделать не выйдет.

Но в Lispworks, например, есть 32-разрядная арифметика, соответствующая int.

На 32-битной платформе? А напиши, как на нём будет unsigned plus(unsigned x, unsigned y) { return x + y; } ?

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

С сильными тормозами по отношению к JS или к оригинальному Pascal

Если брать для Паскаля LLVM, то тормоза будут существенно меньше. А JS по семантике от Лиспа несильно отличается. Хотя за счёт дебаггера и сигнального протокола, думаю, V8 всё равно будет быстрее, чем JS на CL. Но не так существенно. А паскаль поверх CL будет тормознее, чем нормально написанный компилятор JS.

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

unsigned plus(unsigned x, unsigned y) { return x + y; } ?

Документация - здесь: http://www.lispworks.com/documentation/lw61/LW/html/lw-116.htm#76401

Конкретно эту ф-ю не напишу, т.к. нужно идти домой, а declare ftype я слёту не пишу.

А паскаль поверх CL будет тормознее, чем нормально написанный компилятор JS.

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

В JVM у чисел нет тэга типа и на куче они не живут. Там только указатели.

Наверное, в JVM нет типа T?

Возможно, прекомпилированный код JVM и быстрее CL (shootout это показывает), но тот же шутаут показывает, что требования к памяти у CL скромнее. А память против скорости - это тоже нормальный торг. Кроме того, технология JIT в реальной жизни приводит к тормозам.

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

Наверное, в JVM нет типа T?

Есть Object. Включает в себя Integer, но не включает int. Ну и можно через структуры наворотить Object + int + ... . Только тормозно и неудобно будет.

Документация - здесь: http://www.lispworks.com/documentation/lw61/LW/html/lw-116.htm#76401

Понял. Ну да. Здесь не хуже, чем в JVM.

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