LINUX.ORG.RU

Альтернатива Emacs Lisp'у

 , ,


1

3

Лисп сам по себе отталкивает часть программистов, а Emacs Lisp, будучи довольно уникальным лиспом, на котором довольно больно писать как в императивном, так и в функциональном стиле, привлекает subset от итак не особо большого количества ценителей S-выражений и макросов.

Предположим, была бы возможность всё то, что сейчас пишется на Emacs Lisp, реализовывать на каком-нибудь С-подобном языке (для конкретики пусть будет Go) - было бы это, по вашему, полезным? Вы бы попробовали?

Запускать Go вместо Emacs Lisp можно было бы при компиляции Go в байткод Emacs Lisp. Технические детали, наверное, пока можно держать в стороне.

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

Почему тебя это волнует?

Если вам действительно интересно, я вам отвечу.

Это на практике делает невозможным эффективную реализацию, например, расширяемых массивов на C с лисповой мордой. На каждый вызов вашего `ext-vector-ref` будет аллокация, из-за чего в разы будет медленнее, чем в случае с нормальной встроенной функцией. Разница в скорости на порядки, что-то близ «в сотни раз». Для конкретных цифр мне нужно будет найти код, который это проверял.

Реализовать растущие массивы можно и поверх векторов лиспа, на самом же лиспе, но тот же slice из Go эффективно реализовать будет сложнее. Если очень интересно, могу поделиться, почему.

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

Реализовать растущие массивы можно и поверх векторов лиспа, на самом же лиспе, но тот же slice из Go эффективно реализовать будет сложнее. Если очень интересно, могу поделиться, почему.

Интересно, поделись.

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

Допустим, мы начнём с представления вида {data, len, cap}. Data будет вектором. Вместо списка возьмём improper list, где у нас нет финального nil, чтобы немного экономить память:

(cons data (cons len cap))

Если интересно, почему не вектор - тут надо в дизассемблер смотреть. Доступ к спискам из 2-3 элементов - очень эффективный. Чем ближе к голове списка, тем эффективнее. Data чаще всего используется, поэтому он в начале списка.

Операции get/set будут очень эффективными. У нас будет тот же aset/aget, но с overhead на (car slice).

Но что будет, когда вы берёте subslice? В C вы могли бы data сделать указателем и сместить его, куда нужно. Адресация была бы такой же, 0-based. В нашем случае это невозможно, что приводит к необходимости хранить ещё и offset:

(cons data (cons offset (cons len cap)))

Для каждого get/set теперь нужно к индексу прибавлять offset.

Для обычного вектора:

<vector>
<index>
aref
Для slice без поддержки offset:
<slice>
car
<index>
aref
Для slice с поддержкой offset:
<slice>     ;; <slice>
dup         ;; <slice slice>
car         ;; <slice data>
stack-ref 1 ;; <slice data slice>
cdr         ;; <slice data slice.cdr>
car         ;; <slice data offset>
<index>     ;; <slice data offset index>
plus        ;; <slice data real-index>
aref        ;; <slice elem>
stack-set 1 ;; <elem>

Операция set элемента так же разбухает. Как реализовать более эффективно я пока не знаю.

Бенчмарки проводил. Если вместо вектора использовать списки, то мы на всех операциях будем проигрывать на порядки. Если вместо improper списка для slice'а использовать вектор, теряем около 10% производительности + const vector из-за индексов может увеличиться.

quasilyte
() автор топика
Ответ на: комментарий от feofan

А ещё всякие вытекающие проблемы. Насколько мне известно, в Emacs'е нет эффективной функции для копирования элементов из диапазона вектора в другой вектор.

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

Насколько мне известно, в Emacs'е нет эффективной функции для копирования элементов из диапазона вектора в другой вектор.

substring

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

substring

Наверное криво выразился. У вас уже есть 2 вектора (потенциально больших) и нужно из одного перекопировать часть элементов во второй. При этом offset может быть ненулевой.

quasilyte
() автор топика
Ответ на: комментарий от feofan

А почему бы не использовать вместо improper list вектор или hash table? тогда set и get будут работать за O(1).

Для хранения элементов используется вектор. improper list используется для представления структуры (data+offset+len+cap). То есть get/set O(1).

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

Это на практике делает невозможным эффективную реализацию, например, расширяемых массивов на C с лисповой мордой.

Лол. Зачем это делать на практике? Какое _таким_ массивам применение? Ну скопируй данные из массива C в массив Lisp и будет счастье.

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

Наверное криво выразился. У вас уже есть 2 вектора (потенциально больших) и нужно из одного перекопировать часть элементов во второй. При этом offset может быть ненулевой.

Не выглядит как такая уж частая задача

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

[data offset len cap]

Я не спорю, что это корректное представление, но склонен полагать, что для N=3 доступ из списка (учитывая инструкции Emacs Lisp VM) эффективнее. Атрибут «cap» используется реже всех, поэтому даже при N=4 тут выбран список.

Это не критичный аспект реализации, как мне кажется. Наиболее печальное - это требование арифметики со смещением для get/set и... листинг, который я привёл выше, не на 100% конформен к спецификации Go. Нужно ещё добавлять проверку границ массива (ведь у нас может быть слайс, у которого длина меньше, чем размер underlying Emacs Lisp вектора).

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

Это на практике делает невозможным эффективную реализацию, например, расширяемых массивов на C с лисповой мордой. На каждый вызов вашего `ext-vector-ref` будет аллокация, из-за чего в разы будет медленнее, чем в случае с нормальной встроенной функцией. Разница в скорости на порядки, что-то близ «в сотни раз». Для конкретных цифр мне нужно будет найти код, который это проверял.

а как это сейчас выглядит в Xemacs? там вроде были нормальные векторы и массивы.

но тот же slice из Go эффективно реализовать будет сложнее. Если очень интересно, могу поделиться, почему.

tl;dr : ты хочешь за собой тянуть половину рантайма Го, про мусорщик, горутины, слайсы и интерфейсы, зачем?

вангую что мантра «не платишь за то, что не используешь» будет лучше у какого-нибудь раст или сишечки, модули писать на нём.

Го тут как-то не очень.

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

или на Nim писать модули к емаксу, там тоже AST макросы есть и GC отстреливаемый. опять же, оно в сишечку компелируется, то есть на ним теоретически понадобятся только хитровыдуманные макросы.

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