LINUX.ORG.RU

Не учите Common Lisp!

 ,


1

7

Хочу предостеречь форумчан от изучения Common Lisp. Возьмите самую лучшую имплементацию — SBCL и скомпилируйте следуюущие лямбды:

;; Взятие элемента по индексу x из массива x
(lambda (x) (aref x x))
;; Взятие элемента по индексу y из массива x и прибавление к x
(lambda (x y) (+ x (aref x y)))
;; Один из путей выполнения: прибавление X к NIL
(lambda (x y) (+ x (funcall (lambda (x) (if x 0 x)) y)))

Ни на одной из этих бессмысленных функций компилятор не ругнётся. Вы скажете: «А что такого? Это же язык с динамической типизацией!» А то, что если вы хотите хоть насколько нибудь быстрого кода, вам нужно делать какие-то утверждения о типах, производя только лишь статический анализ кода.

Минус коммон лиспа как языка — слишком разрешательский стандарт. Почти сплошь и рядом там фразы вроде «Эффект, производимый объявлением inline, определяется реализацией» или «Реализация вольна игнорировать то-то и вместо этого делать то-то». Из-за этого разработчики того же SBCL будут игнорировать твои баг репорты, где из-за неправильного поведения компилятора (с точки других опубликованных алгоритмов) твой код будет работать раза в 2 или 3 медленнее, чем должен бы.

Написали бы в стандарте «реализация ДОЛЖНА поступать так-то и так-то», и можно было бы тыкать разрабов носом в это место и требовать корректного поведения. А раз написали «реализация может делать, что ей захочется», то и прижучить их нельзя. В итоге все занимаются чем хотят, кроме починки багов.

Короче, учите языки с хорошей теоретической базой и статической типизацией. Байкам @lovesan не верьте ни одной.



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

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

(defun array-multisort (&rest arrays)
    (let* ((keys (car arrays))
        (sorted-keys (sort (copy-list keys) #'<))
        (sorted-arrays (mapcar (lambda (array)
                               (mapcar (lambda (key)
                                       (nth (position key keys) array))
                                sorted-keys))
                                (cdr arrays))))
    (values-list (cons sorted-keys sorted-arrays))))

(defvar *list1* '(10 1 0 100))
(defvar *list2* '(1 3 2 4))

(multiple-value-bind (sorted-list1 sorted-list2) (array-multisort *list1* *list2*)

(format t "Sorted list1: ~a~%" sorted-list1)
(format t "Sorted list2: ~a~%" sorted-list2))
Sorted list1: (0 1 10 100)
Sorted list2: (2 3 1 4)

Хотя скорее всего с одинаковыми элементами в первом списке правильно работать не будет тк там нужно проверять это момент, а я и так уже потратил четверть месячной зарплаты лиспера 20 минут. Уверен, вы сами в состоянии дописать эту часть, тк знаете Lisp лучше меня (тут без подкола, что есть то есть), но вам также лень как и мне.

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

Прошу прощение за небрежение нашей дискуссией. Занят выбором автомобиля, голова кругом идёт и вообще не соображет уже. Возможно поэтому снова неудача

php > echo $n;
4
php > echo pipe('$n | $x + 1');

Warning: Undefined variable $n in php shell code(5) : eval()'d code on line 1
1

Что делать?

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

Вот как в Lisp удобно пометить что поле в defstruct имеет специальное имя при экспорте в формате ABCD?

defstruct так не умеет. Но это и не важно, когда у тебя есть друзья наркотики макросы!

(defmacro defstruct-with-meta (name &key (meta) fields)
  (let* ((package (symbol-package name))
	 (fn (~> (format nil "META-~a"  name)
		(intern package))))
    `(progn
       (defstruct ,name ,@fields)
       (defun ,fn () ,meta))))

Если непонятно, здесь мы создаём макру, которая при раскрытии создаёт структуру с помощью defstruct и вспомогательную функцию, возвращающую метаинформацию. Куда можно положить всё, что угодно, включая рекомендации по трансформации имён в разных форматах. Например,

(defstruct-with-meta user
  :meta '((:csv . 'camel-case) (:yaml . 'snake-case))
  :fields
  (id
  (first-name "John" :type string)
  (second-name "Doe" :type string)))

После чего можно будет пользоваться ими (структурами и функциями) как родными

CL-USER> (setf u1 (make-user :id 1 :first-name "a" :second-name "b"))
#S(USER :ID 1 :FIRST-NAME "a" :SECOND-NAME "b")
CL-USER> (user-first-name u1)
"a"
CL-USER> (meta-user)
((:CSV QUOTE CAMEL-CASE) (:YAML QUOTE SNAKE-CASE))

Ваш ход, как научить php добавлять к структурам метаинформацию?

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

Lua, точно. Уже пыхерам не так одиноко, есть с кем курнуть. А нафига вы полтреда обсуждаете это недоразумение? Кстати, список пхпшных батареек не такой уж внушительный, чтобы им так размахивать. Вон в руби только для хэштаблиц больше сотни методов, например. Никогда не понимал зачем всё это пихать в стандартную либу. Чтобы рантайм пожирнее был что ли.

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

, то что есть в php, чего нет в лиспе?

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

ugoday ★★★★★
()
Ответ на: комментарий от Obezyan
(defvar *list1* '(10 1 100 100))
(defvar *list2* '(2 3 4 1))

(defun multisort (&rest lists)
  (labels ((tuple-compare (l1 l2)
             (and l1
                  (or (< (car l1) (car l2))
                      (and (= (car l1) (car l2))
                           (tuple-compare (cdr l1) (cdr l2)))))))
    (apply #'mapcar #'list
           (sort (apply #'mapcar #'list lists) #'tuple-compare))))
CL-USER> (multisort *list1* *list2*)
((1 10 100 100) (3 2 1 4))

Только это сортировка списков, а не той неведомой хтони, что в https://www.php.net/manual/en/function.array-multisort.php

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

Хорошая попытка. Почти получилось.

CL-USER> (multiple-value-bind (sorted-list1 sorted-list2) 
	     (array-multisort '(10 100 100 0) '(1 3 2 4))
	   (format t "Sorted list1: ~a~%" sorted-list1)
	   (format t "Sorted list2: ~a~%" sorted-list2))
Sorted list1: (0 10 100 100)
Sorted list2: (4 1 3 3)
ugoday ★★★★★
()
Ответ на: комментарий от Obezyan

Я хочу посмотреть как: a) threading macros могут быть реализованы на php; б) как на практике вообще работает метапрограммирование через обработку строк + eval.

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

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

Если на лиспе написать php, хостинг с ним не появится.

Так и не надо. Пишем на лиспе, потом транслируем на php и вжух, открываем с ноги дверь в мир дешманского хостинга.

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

Пишем на лиспе, потом транслируем на php и вжух, открываем с ноги дверь в мир дешманского хостинга.

Так для этого надо не php на лиспе писать, а лисп на php. И их пару штук написали: до CL далеко, но хоть макросы есть.

А если php на лиспе, то это наоборот позволило бы писать на php и запускать на лиспе. Как есть cl-javascript.

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

Я хочу посмотреть как

Я тоже «хотел посмотреть как». В итоге писал код за обе-три стороны (php/lisp/clojure). Давайте там уже сами как-нибудь.

eval - evil. Не надо его использовать. Трубные варианты Морковки лучше, их можно раскручивать добавляя вещи типа:

$Bar = "a";
$Foo = "Bar";
$World = "Foo";
$Hello = "World";
$a = "Hello";

print(implode(' ', [$$$$$$a, $$$$$$$a])); // Hello World
Obezyan
()
Последнее исправление: Obezyan (всего исправлений: 1)
Ответ на: комментарий от monk

Да, действительно. Вы всё правильно написали.

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

В итоге писал код за обе-три стороны (php/lisp/clojure)

Я проглядел или php-реализация многомассивной сортировки была где-то представлена?

eval - evil. Не надо его использовать. Трубные варианты Морковки лучше,

Не подскажете, что делает eval("return $cmd;"); в его коде?

Насчёт print(implode(' ', [$$$$$$a, $$$$$$$a])); // Hello World кажется, вы дичайше наелись незрелых бананов. Не надо так, не бережёте вы себя.

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

Я проглядел или php-реализация многомассивной сортировки была где-то представлена?

array_multisort()

Не подскажете, что делает eval(«return $cmd;»); в его коде?

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

Насчёт print(implode(’ ’, [$$$$$$a, $$$$$$$a])); // Hello World кажется, вы дичайше наелись незрелых бананов. Не надо так, не бережёте вы себя.

Это метабананы.

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

array_multisort()

Да, я видел. А теперь, пожалуйста, такое же, только на php.

В данном случае является замыканием

Не понял. Попробую завтра перечитать, может лучше дойдёт.

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

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

А чтобы у каждого экземпляра структуры была своя мета?

Вообще, наверное, не очень удачная идея хранить такие настройки привязанными к самой структуре — а что, если мы захотим в каком-то отдельном случае экспортнуть её с другими настройками?

Скорее пусть они хранятся в конфигурации кода, занимающегося экспортом.

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

А чтобы у каждого экземпляра структуры была своя мета?

Добавить в структуру соответствующее поле. Чем эта «мета» тогда отличается от обычной информации?

Скорее пусть они хранятся в конфигурации кода, занимающегося экспортом.

Да я тоже так думаю, но если уж хочется добавлять метаинформацию, вот, есть способ. Правда целых 7 строк кода пришлось написать, а в других языках — не надо. Просто ждёшь лет 10-15, пока комитет примет новый стандарт, а индустрия реализует его в новых компиляторах и готово, пиши, радуйся, добавляй мета-метки к своим структуркам.

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

Ваш ход, как научить php добавлять к структурам метаинформацию?

Там есть атрибуты, просто

#[MoyaInfa]
private int $field;

Но в С я действую по другому, например в метапроге для каждого типа свой цвет

#define metaprog_type_x \
  x(INT, "Целое", COLOR_BLUE) \
  x(BOOL, "Да/Нет", COLOR_GREEN) \
  x(FLOAT, "Дробное", COLOR_ORANGE) \
  x(STRING, "Строка", COLOR_MAGENTA) \
  x(VOID, "Пустота", COLOR_GRAY)

enum metaprog_type {
#define x(c, name, color) METAPROG_TYPE_ ## c,
  metaprog_type_x
#undef x
};

struct {
  const char *name;
  enum color color;
} metaprog_type_info[] = {  
#define x(c, name, color) {name, color}, 
  metaprog_type_x
#undef x
};
Готово, есть таблица с метаинформацией, и заполненный enum. Если таблица не нужна в runtime, ее можно не создавать а таким же способом сделать switch в коде.
void print_type(enum metaprog_type t)
{
  printf("Имя %s, цвет %s\n", metaprog_type_info[t].name, color_name(metaprog_type_info[t].color));
}

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 4)
Ответ на: комментарий от ugoday

Да я тоже так думаю, но если уж хочется добавлять метаинформацию, вот, есть способ. Правда целых 7 строк кода пришлось написать, а в других языках — не надо. Просто ждёшь лет 10-15, пока комитет примет новый стандарт, а индустрия реализует его в новых компиляторах и готово, пиши, радуйся, добавляй мета-метки к своим структуркам.

Я очень часто это слышал, и мне всегда казалось что очень неправдоподобной критикой.

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

Я оцениваю написание своего препроцессора на TCL и добавление удобного способа добавлять структуры с метаинформацией в максимум 500 строк.

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

А теперь, пожалуйста, такое же, только на php.

Вы пропустили ту часть где мы обсудили что php написан на С с ассемблерными вставками, что не отменяет того что array_multisort() написан ДЛЯ интерпретатора PHP, а Лисп в основном пытается дергать ЧУЖИЕ наработки.

И Common Lisp и SBCL также частично написаны на C, так что ваша попытка ухватиться за идею о том что эта функция не являются частью PHP обречена на провал.

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

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

Я хочу посмотреть как: a) threading macros могут быть реализованы на php; б) как на практике вообще работает метапрограммирование через обработку строк + eval.

Тот наколеночный код вообще не по феншую. Правильно нужно делать через функторы. Для литералов соответственно нужен конструктор/фабрика функторов. eval не нужен, с ним всё будет через жопу работать.

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

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

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

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

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

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

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

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

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

Для литералов соответственно нужен конструктор/фабрика функторов.

Когда еще не отошел от встроенных функций PHP, а тебя уже глушат абстрактными фабриками фабрик функторов :)

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

Судя по echo $arr[0]["b"]["B"], "\n"; вы хотели 2.

Глянул - у них есть встроенная функция make-array которая позволяет примерно тоже самое.

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

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

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

Можно взять любой скриптовый язык и превратить его в препроцессор,

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

Лисповая макра работает изнутри, обладает всей информацией о семантике/синтаксисе/структурах данных. Плюс изнутри макроса можно вызвать любой другой макрос или функцию, которые вообще писались без всякого знания о том, что их будут внутри макросов использовать. (сравни, например, С++, где template’s образуют особый мир).

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

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

Признаюсь, я в тайне лелеял план получить код на php, создать csv’шку гигабайт на 20 и померить производительность. Было бы весело. Но то, с какой настойчивостью и упорством пхп-шники избегают написания пхп-кода, является прекрасным фактом само по себе. С другой стороны, я вас понимаю и ничуть не осуждаю, если бы злая нужда заставила меня писать на пхп, я б тоже делал это только за деньги и в рабочее время.

SBCL также частично написаны на C

По удивительному стечению обстоятельств сишный код лежит в папочке src/runtime. Интересно, что бы там было.

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

Можно так

defvar *list1* '(10 1 100 100)
defvar *list2* '(2 3 4 1)

defun multisort (&rest lists)
  labels 
    \\
      tuple-compare (l1 l2)
        and l1
            or {car(l1) < car(l2)}
               and {car(l1) = car(l2)}
                   tuple-compare cdr(l1) cdr(l2)
    apply #'mapcar #'list
      sort 
        apply #'mapcar #'list lists
        #'tuple-compare
monk ★★★★★
()
Ответ на: комментарий от ugoday

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

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

Для С в этом случае будет лучше всего написать плагин для компилятора, https://github.com/torvalds/linux/blob/master/scripts/gcc-plugins/structleak_...

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

По удивительному стечению обстоятельств сишный код лежит в папочке src/runtime. Интересно, что бы там было.

GC например, почему на лиспе не смогли написать GC?

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

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

По факту, в лиспе на макросах реализовали ООП. В сишке для этого пришлось писать С++. Потому что метопрограммирование на макросах удобное, а на строчках — нет.

нужно залезть во внутрь компилятора,

В мире лиспа эта фраза бессмысленна. Макрос это функция, которая работает на стадии compile-time (и, соответственно, меняет компилятор), reader-macros позволяет произвольно менять синтаксис, в том числе отказаться от скобок или перейти к инфиксной записи (но никому это не нужно, потому что скобки это не проблема, скобки это решение), eval-when точно сказать, на какой стадии исполнения использовать код, а виртуальные операции указывать в какой конкретно ассемблерный код развёрнётся наша писанина.

При этом между использованием этих возможностей и написанием оперденя или билинга. Нет такого, что одни люди пишут php, другие люди — пишут на php.

Для С в этом случае будет лучше всего написать плагин для компилятора

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

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

А вот не буду врать, тут я выхожу за область своих знаний. Мой уровень — метациклический интрепретатор схемы, компиляторов уровня sbcl писать не приходилось.

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

По факту, в лиспе на макросах реализовали ООП. В сишке для этого пришлось писать С++.

cfront от Страуструпа это как раз препроцессор.

В мире лиспа эта фраза бессмысленна

Нет конечно, ты кидаешь ссылку где используются внутренности SBCL, то есть внутренности компилятора. Невозможно расширить Lisp просто средствами языка на который есть стандарт, нужно подключаться к компилятору.

Иначе какая разница между С и Lisp? В C тоже функция превращается в объектный файл, и даже может не знать что вызывается из компилятора.

https://pvk.ca/Blog/2014/08/16/how-to-define-new-intrinsics-in-sbcl/

Там ничего нету из того что я перечислил, более того, даже не заводится новая команда. Читал сам? То что там, это скорее аналог __asm__ в С.

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

Нет, это не плагин для sbcl. У него вообще плагины есть? Есть ли API предназначенное для расширения, или нужно переопределять функции в надежде что в следующей версии не сломают?

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от ugoday

А чтобы у каждого экземпляра структуры была своя мета?

Добавить в структуру соответствующее поле

Это может сработать, если структура ассоциативная — просто добавляем служебное поле, которое при экспорте игнорируем. Ну окей.

А если это список или массив? Добавим в начало/конец служебный элемент и будем игнорировать его при экспорте? А если это множество?

Как по мне, смешивать данные и конфигурацию — не очень хорошая идея.

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

cfront от Страуструпа это как раз препроцессор.

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

Невозможно расширить Lisp просто средствами языка на который есть стандарт, нужно подключаться к компилятору.

Неразобрал эту фразу. Что вы называете «подключаться к компилятору»?

Иначе какая разница между С и Lisp?

Напишите мне аналог макроса loop на С. Хотя бы частично.

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

Что такое команда? Чем она должна отличаться от функции или макроса?

Нет, это не плагин для sbcl.

А почему? Чего не хватает?

Есть ли API предназначенное для расширения

https://www.lispworks.com/documentation/HyperSpec/Body/m_defmac.htm

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

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

type user struct {
    Id           string `json:"id"`
    FirstName    string `json:"firstName"`
    LastName     string `json:"lastName"`
}

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

ugoday ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.