LINUX.ORG.RU

Вопрос про историю лиспа

 , ,


2

2

Мне понравилось замечание в SICP что у лиспа довольно специфичный взгляд на синтаксический сахар. Но вот я не могу понять почему в таких формах из CL как cl:defun или cl:destructuring-bind у ключевых симоволов &key, &optional приставка & вместо использования более адекватных для CL кейвордов?

★★★★★

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

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

Это ты к чему? Бредишь? Или утверждаешь, что «COBOL, Ada, Java и C#» - наследники схемы?

Утверждаю, что кроме языков «для инженеров» есть языки для нормальных людей и они не исчерпываются академическими и учебными.

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

Нормальный человек предпочитает изучать, как выполнить задачу и как спроектировать эффективный и надёжный алгоритм, а не изучать, как обойти неустранимые недостатки инструмента. «Знания» всех UB в Си и всех опасных конструкций лиспа не делает человека инженером, а делает его лишь профессиональным пользователем инструмента.

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

Утверждаю, что кроме языков «для инженеров» есть языки для нормальных людей и они не исчерпываются академическими и учебными.

Ты с кем споришь? Я сразу написал: 99-и процентам современных программистов лисп не только не нужен, а даже вреден.

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

Для выполнения типичной задачи. И можно про неустранимые недостатки?

«Знания» всех UB в Си и всех опасных конструкций лиспа не делает человека инженером, а делает его лишь профессиональным пользователем инструмента.

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

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

префиксные выражения, которые строки и expr в тикле это боль, всё остальное секси

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

Первые два пункта это про отсутствие какой-либо итерации в дизайне, причина последнего - изначально «велосипед», «костыль». Ничто, правда, не мешает посмотреть на правильную эволюцию реализации нишевого языка - chez scheme. Похвалу и выбор «за» именно работу с памятью можете поискать на stackoverflow, производительность - ну не знаю, прогоните фибоначи, спискомолотилки и увидите что уровень свеженького ghc (chez это aot как и sbcl), если взять bytevectors это вообще будет как C, и ничего в этом удивительного нет. Последний пункт - это просто миф (кроме эзотерики), в раст просто непродуманный и от это избыточный синтаксис, а после ебли с гениальной концепцией наследования/заимствования, необходимости погуглить, чтобы передать функцию в функциию и понимания того, что в реализации до сих пор есть баги вроде «сделал переменную mut и цикл отработал на три порядке быстрее», вы поймёте что, это совершенно очередной обычноый ЯП, который сам съел все свои печеньки.

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

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

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

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

ни если другие невмендосы думают что на ней что-то там исследуют

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

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

Его основные претензии к отсутствию в ЦЛ гигиены, что лечится. Кстати, негигиенические макросы в лиспе возможны, а в Ракете нет.

это не претензии к реализации, в скимах, в которых реализован syntax-case(а уж ракет это просто гетто всяких велосипедов) гигиену можете ломать без проблем. К слову, гигиена для скима просто идиоматична, и вообще полезная вещь,а смотреть на вещи можно под разными углами

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

Вторая большая - отсутствие продолжений. Это обусловлено архитектурой и мееееедлиииитеееельносью продолжений.

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

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

Основная претензия — щедро рассыпанные грабли как в Си. Активное использование деструктивных операций над списками и при этом общих хвостов списков. Возможность сделать деструктивную операцию над литералом!

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

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

Это совершенно не те кривые и смешные костыли, которые в жабе, а просто представление fixnum(число влезающее в указатель, при сравнении указателей естественно равно само себе).

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

Естественно. Если указатели тегированные, то immediate типы боксить не надо. В жабе до такого не додумались когда-то, а теперь уже поздно.

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

да в схеме сделай циклический список

А в чём проблема? Можно даже неизменяемый: #0='(1 2 3 . #0#)

или подумай над реализацией на векторах

В реализации на векторах vector-append всегда возвращает новый вектор. B литеральный вектор всегда неизменяемый.

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

И можно про неустранимые недостатки?

Я же писал уже. В макросах невозможна нормальная гигиена. Только соглашение о том, что нельзя даже локально затенять символы из CL спасает. Нет раздельной компиляции: compile, compile-file, load и eval одной и той же функции могут дать 4 разных результата. Нет нормальных констант: случайная передача литеральной строки или любого не-атомарного defconstant в функцию, изменяющую свой параметр приводит к трудноуловимым ошибкам.

Нет нормальной системы типов/контрактов. Скажем проверить, что переданная аргументом функция имеет правильный тип нереально. Соответственно, ошибки проявляются не там, где они сделаны (при передаче аргумента), а на несколько уровней ниже (где функцию попытались запустить).

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

Нет механизма для генераторов аналогичного питоновскому yield.

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

Это обусловлено архитектурой и мееееедлиииитеееельносью продолжений.

Chez scheme по скорости практически равен sbcl. Если в sbcl не отрубать безопасность, то даже Racket почти равен.

Более того, даже в Си есть продолжения в виде setjmp/longjmp. Не сказал бы, что сильно медленные.

продолжения, как оказалось - зло

Нужны или продолжения или корутины и генераторы как основные абстракции на продолжениях. Генераторы в общелиспе приходится делать через явное отслеживание состояния, а корутины через потоки. Нормальных абстракций нет. Хотя они есть даже в питоне.

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

Chez scheme по скорости практически равен sbcl. Если в sbcl не отрубать безопасность, то даже Racket почти равен.

Не подскажешь как в них (чез и ракета) запустить несколько потоков и привязать каждый из них к отдельному ядру?

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

Не подскажешь как в них (чез и ракета) запустить несколько потоков и привязать каждый из них к отдельному ядру?

В chez есть fork-thread, в Racket есть place.

Привязать к ядру можно через вызов соответствующих сишных функций: для линукса что-то вроде (pthread_setaffinity_np (pthread_self) 4 1)

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

А в чём проблема? Можно даже неизменяемый: #0='(1 2 3 . #0#)

проблем нет, это равносильно присваиванию через set!, и в результате то «что сэкономлено» придётся тратить на копирование

с векторами тоже всё хорошо, но это уже императивненько, и например взятие первого элемента из вектора, который в другом векторе на порядок медленнее чем то же самое для списков, хотя это может и implementation depended

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

в open music CL скорее боком, есть кстати аналогичная среда для композиции, и выглядит лучше намного - opus modus, по ходу её переписали на кажуру хотя изначально вроде была на CL

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

Как в лиспах нынче принято делать локализацию?

Прости, не имею представления.

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

и да opus modus - !!! ком-мер-чес-кий, с-о-ф-т, на, Л-И-С-П-Е, карл

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

Ещё интересный вариант:

#lang racket

(define cyclic-sequence 
  (in-cycle (list 3 4 5)))

(for/list ([elt cyclic-sequence]
           [i (in-range 13)])
  elt)

'(3 4 5 3 4 5 3 4 5 3 4 5 3)

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

Ракетку не знаю, но код понял, глянув на что ты отвечаешь. Но...

Надолго завис да так и не понял, зачем использовали квадратные скобки? В Рекете дефицит круглых?

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

На самом деле в лиспе скобок нет. Просто это далеко не каждый понимает. А некоторые их даже различают.

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

проблем нет, это равносильно присваиванию через set!, и в результате то «что сэкономлено» придётся тратить на копирование

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

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

???

a[3][0] медленнее, чем a->next->next->next->data->data ?

Если даже брать первый элемент первого элемента, то список будет не быстрее.В массиве **a, в списке a->data->data.

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

Надолго завис да так и не понял, зачем использовали квадратные скобки? В Рекете дефицит круглых?

Человеку так читать удобнее. В Ракете (и, вроде, вообще в Схеме) пары круглых и квадратных скобки взаимозаменяемы

> '[1 2 3]
'(1 2 3)
monk ★★★★★
()
Ответ на: комментарий от monk

Человеку так читать удобнее.

Бред!

В Ракете (и, вроде, вообще в Схеме) пары круглых и квадратных скобки взаимозаменяемы

А почему только квадратные? Есть еще фигурные. Если не хватит - скажи, накидаю с десяток вариантов.

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

Бред!

Ну сравни сам:

(let ((i a) (j (b c) (d e)) (k (i b))) (f i b j k d))
и
(let ([i a] [j (b c) (d e)] [k (i b)]) (f i b j k d))

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

А почему только квадратные? Есть еще фигурные.

Их тоже можно:

> '{1 2 3}
'(1 2 3)
но обычно двух видов хватает.

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

Для перевозки на дачу десятка кирпичей достаточно жигуленка (любой легковушки ц-класса)

Нынешний класс C уже сравнялся по размерам с «волгой». Ведь каждое новое поколение любой популярной модели обязательно делают больше пл размерам предыщущего.

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

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

Сравнил. Если в списке не больше двух простых подсписков:

(let ((i a) (j b c)))
(let ([i a] [j b c]))

выгоды от квадратных скобок нет, а более длинные выражения надо форматировать:

(let ((i a)
      (j (b c) (d e))
      (k (i b)))
  (f i b j k d))

или даже:

(let ((i a)
      (j (b c)
         (d e))
      (k (i b)))
  (f i b j k d))

Да и в емаксе есть подсветка скобок.

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

И скажи, пожалуйста, как в ракете записать вызов функции с несколькими аргументами, а в качестве аргументов, функции с аргументами? Например:

(define (aver a b) ...  - среднее от a и b
(define (fact n) ...    - факториал
(define (fib n) ...     - фибоначчи

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

UPD Надо найти среднее от факториала и фибоначчи

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

выгоды от квадратных скобок нет ... и в емаксе есть подсветка скобок

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

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

или даже:

...
      (j (b c)
         (d e))
...

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

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

В длинном выражении без подсветки плохо видно в обоих вариантах - только форматирование спасает. А с подсветкой теряется смысл разных скобок.

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

Правильно.

Получается что вызов вложенной функции без параметров и с параметрами используют разные синтаксические конструкции?

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

Лисп для людей, что ли?

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

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

Получается что вызов вложенной функции без параметров и с параметрами используют разные синтаксические конструкции?

Почему разные? Всегда (имя-функции аргумент ...). Без параметров (aver (fib) (fact)), с параметрами (aver (fib n) (fact n)).

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

В длинном выражении без подсветки плохо видно в обоих вариантах - только форматирование спасает.

Это уже вопрос вкуса и привычек. Также как в Си. Почему if (...) { ...} else { ...}, а не if (...) (...) else (...)? Или не как в Tcl if {...} {...} else {...}. Им так легче читать.

Мне после Racket первые 15 минут читать что-то вроде https://gitlab.common-lisp.net/iterate/iterate/blob/master/iterate.lisp#L1049 достаточно неудобно. (info ...) воспринимается как «скорее всего вызов функции», а не условие cond. Ну и "((...)" в CL будет наверняка особой формой (условие cond или что-то такое), а в Racket легко может попасться что-то вроде ((make-predicate params) value), которое на CL надо писать как (funcall (make-predicate params) value).

monk ★★★★★
()
Ответ на: комментарий от monk
(define (my-random)
  (random 100))

Правильный вариант?

(aver (my-randon) (fact 10))

Или возможно?

(aver my-randon (fact 10))

Если второй вариант невозможен, то в чем смысл lisp-1?

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

Мне после Racket первые 15 минут читать что-то вроде https://gitlab.common-lisp.net/iterate/iterate/blob/master/iterate.lisp#L1049 достаточно неудобно.

То есть через 15 минут неудобство пропадает? Получается квадратные скобки нужны только тем, кто переключается на разные языки каждые 15 минут :)

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

Если второй вариант невозможен, то в чем смысл lisp-1?

Второй вариант невозможен и эквивалентен (aver #'my-randon (fact 10)) в CL.

Смысл lisp-1 в том, что не приходится использовать function и funcall (а также flet/labels в дополнение к let/let*).

(let ([add2 (compose add1 add1)])
  (f (add2 x) (add2 y)))

Вот как это в CL правильно делать?

(flet ((add2 (x) (funcall (compose add1 add1) x)))
  (f (add2 x) (add2 y)))
или
(let ((add2 (compose add1 add1)))
  (f (funcall add2 x) (funcall add2 y)))
или
(let ((add2 (compose add1 add1)))
  (flet ((add2 (x) (funcall add2 x)))
    (f (add2 x) (add2 y))))
?

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

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

Можно и так сказать. Хотя в схеме они чуть нужнее, чем в общелиспе из-за упомянутой неоднозначности "((...) ...)", если квадратные скобки не использовать. Впрочем, чистой воды вкусовщина. Даже в схеме не во всех реализациях есть квадратные скобки.

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

В длинном выражении без подсветки плохо видно в обоих вариантах - только форматирование спасает. А с подсветкой теряется смысл разных скобок.

для тех кого напрягают скобки в блоке переменных let/let*:

(define-syntax go
  (syntax-rules ()
    ((_) '())
    ((_ r) r)
    ((_ (e ...) r ...)
     ((lambda () (e ...) (go r ...))))
    ((_ l v r ...)
     ((lambda (l) (go r ...)) v))
    ))
пример:
(go a 3
    b 2
    - /
    + *
    (display
     (list a b (- a b) (+ a b)))
    (newline)
    a b
    b 10
    (list a b)
    )

> (3 2 3/2 6)
  (2 10)

заменяет let, let*, begin, сломается, например, на (go 1 2), но в таких выражениях мало смысла

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

И как сделать c этим чудом аналог ...

там видно что это:

(go a 1
    b 2
    (display (list a b))
    (newline)
    (go a b
	b a
	(display (list a b))
	(newline)))
аналог вот этого:
(let* ((a 1) (b 2))
  (display (list a b))
  (newline)
  (let* ((a b) (b a))
    (display (list a b))
    (newline)))

да, let не заменяет, но это не страшно

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

ну можно так, лишь бы скобки не писать, шютка:

(go a 1
    b 2
    (display (list a b))
    (newline)
    (go c a
	a b
	b c
	(display (list a b))
	(newline)))

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

мне вот let* чаще нужен чем let, намного, плюс переопределять/определять переменные можно в любом месте, да в ракете можно define всунуть в любом месте, но в других скимах - нет, и так локаничнее

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

А что серьёзного я могу на Racket-е увидеть? Может использует какая компания в продакшене и есть исходники, хочу посмотреть как люди пишут в боевых условиях

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