LINUX.ORG.RU

Lisp: Где применимы cons?

 cons,


1

6

Для начала небольшой «бенчмарк», С без всех оптимизаций в 7406000 раз быстрее.

(defun main ()
  (declare (optimize (speed 3)))
  (let ((n 99999) (l '()) (sum 0))
    (loop for i from 0 to n
	  do (setq l (append l (list i))))
    (setq sum 0)
    (loop for i from 0 to n
	  do (setq sum (+ sum (nth i l))))
    (format t "~d~%" sum)))
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv)
{
	long n = 99999, *l = NULL, count = 0, sum = 0;
	for (long i = 0; i <= n; i++) {
		l = realloc(l, (count + 1) * sizeof(long)); 
		l[count++] = i;
	}
	for (long i = n; i >= 0; i--) sum += l[i];
	printf("%ld\n", sum);
}

Для чего же нужны cons? В качестве универсального строительного блока, я считаю это одна из самых худших структур. Все ее преимущества заканчиваются на быстром добавлении в начало. Добавление в конец уже нежелательно, разрез в произвольном месте тоже, так как нету даже быстрого доступа к случайному элементу. Она медленная и неудобная, можно придумать кучу более быстрых и удобных структур. Даже JS на световые годы опережает Lisp со своим JSON, и его частое использование лишь подтверждает его удобство.

Так почему же cons из языка-ассемблера IPL 1956 года считается важным? Да, это неплохая структура для AST, если ваша машина имеет 16 кб памяти, но она распространилась по языку слишком широко.

★★★★★

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

Ну так и в Forth можно сделать проверку типов, а на счет фразы, видно неиспользованное слово МЕДЛЕННО, но если тебе так не нравится эта линия, то можно просто переформатировать:

Левый Верхний Рычаг
20 Медленно Повернуть 

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

у вас нет никаких автоматических проверок корректности ваших выражений. можно вместо ПОВЕРНУТЬ БЫСТРО, написать БЫСТРО ПОВЕРНУТЬ?

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

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

Лол, это свопать на стеке ячейки

Можно использовать локальные переменные, но использование swap, rot, over, nip приводит к более простому и короткому коду чем с переменными.

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

Это все абстрактная схема, в реальности компиляторы все это в регистры оптимизируют, если так быстрее. Ну и к слову об адекватности, вспомни как был устроен x87.

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

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

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

Рычаг.Левый().Верхний().Повернуть(20,Медленно)

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

И всё равно необходимость реализовывать обработку Медленно отдельно для Повернуть, отдельно для Опустить, отдельно для Поднять…

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

у вас нет никаких автоматических проверок корректности ваших выражений. можно вместо ПОВЕРНУТЬ БЫСТРО, написать БЫСТРО ПОВЕРНУТЬ?

Будет неверное выполнение и неверное состояние стека после слова БЫСТРО. Первый же тест обнаружит.

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

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

И всё равно необходимость реализовывать обработку Медленно отдельно для Повернуть, отдельно для Опустить, отдельно для Поднять…

вы не поверите, но медленно бежать и медленно ползти - это разные медленно. я вот очень сомневаюсь, что ваше медленно имеет один и тот же смысл в разных применениях.

но если мы перейдем к строгим высказываниям и назовем медленно - как (0.2 * максимальнная_скорость) - то «медленно» станет универсальным для всех применений.

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

неверное состояние стека после слова БЫСТРО

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

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

Основная проблема тестирования надёжных систем

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

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

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

Малореальная ситуация, но вообще, отдельный теггированный стек с выбросом исключения это две строки на моем диалекте, или около 5 на ANS Forth.

Кстати, заметь что если один и тот же тип, аргументы в том же порядке, то и С++ тебя не защитит.

А надежность стека+словаря и программ в подобном стиле, подтверждается рабочими парсерами на базе словаря (или на базе макросов, как удобнее воспринимать) у автора sp-forth.

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

Я к тому, что неверный порядок слов даст ошибку (результат, не соответствующий ожидаемому) почти в любом тесте, который через эту строку пройдёт. А вот неверное значение константы по отношению к внешнему устройству отследить синтетическим тестом гораздо сложнее: только проверкой уже на реальном устройстве.

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

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

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

swap, rot, over, nip приводит к более простому и короткому коду чем с переменными.

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

и внутри стековой машины, будет все равно более эффективное регистровое ядро. поэтому регистры и явное указание операндов и доминирует.

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

Кстати, заметь что если один и тот же тип, аргументы в том же порядке, то и С++ тебя не защитит.

Защитит. Они будут возвращать разные типы, и потому их будет нельзя перепутать.

Естессно порядок применения задается типизацией, если он важен. Если порядок применения неважен - тип будет один. Все как доктор прописал

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

А всем прочим штукам, они неадекватны и общий код длиннее, чем регистровый.

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

Посмотри на код который предоставил monk с рычагом, там нету swap. Может внутри он будет, но ты надеюсь понимаешь что swap либо выбрасывается, либо превращается через опкод в переименование регистра, что довольно дешево. Так вот, никакой настройки, пересылки из rax в rdx, или очистки стека, потому что стек чистится операциями.

и внутри стековой машины, будет все равно более эффективное регистровое ядро

На x86 безусловно, на настоящих стековых машинах верхушка стека закешированна, можно сказать что это регистры, а можно так не говорить.

поэтому регистры и явное указание операндов и доминирует.

Много где стековая модель, даже в биткоин засунули, и JVM.

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

Защитит. Они будут возвращать разные типы, и потому их будет нельзя перепутать.

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

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

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

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

Много где стековая модель, даже в биткоин засунули, и JVM.

это чисто абстракция. это Вирт еще вроде начал, с его P-кодом.

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

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

шитый это просто адреса, со всеми вытекающими. то есть не менее 32 бит на команду(если без адреса или константы). а стековые машины имеют команду в байт в основном. кроме load/store. короче шитый код - самый длинный небось.

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

это чисто абстракция. это Вирт еще вроде начал, с его P-кодом.

Как и регистры и стек, да. Или ты думаешь rax это железный неизменный rax?

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

Никогда не слышал о преимуществах для компиляции арифметических выражений, расскажи?

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

Тип команды пару бит, дальше в зависимости от типа команды, дальний или короткий переход может быть какое угодно значение. По сравнению с x86 можно избавится от большого префикса опкодов, их будет очень мало, и от rex префиксов всяких. А тот же ret в один байт легко запихать, на него выделить особое место в этой системе.

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

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

:) ну не всё так однозначно

вобщем то вполне просто слово которое подобно литу ( lit ) типово заводит локальные переменные сжирая входной поток до терминатора ;

int a b c ;

теперь у нас слова локальные переменные :)

имхо все остальное прикольно но не так как разделение стека извратов от стека аргов

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

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

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

Никогда не слышал о преимуществах для компиляции арифметических выражений, расскажи?

тривиальный однозначный генератор.

x = (a+b*c-d)

load a
load b
load c
mul
add
load d
sub
store x

никаких регистров, и зависимости от контекста генерации.

а ты не знал, или прикидываешься?

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

и сколько если шитый код. команда без операнда не менее 4 байт.

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

Из за упоминание компиляции, я подумал не про разбор/трансформацию, а больше о оптимизации и x86 vs SSE. А про перевод из инфиксной нотации еще в первых работах Чарльза Мура упоминается, востребованная штука для форт-систем, в которых работали пользователи.

и сколько если шитый код. команда без операнда не менее 4 байт.

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

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

шитый код тоже может быть динамического размера как и нативный.

может. тогда все вырождается просто в switch.

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

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

может. тогда все вырождается просто в switch.

Там не только switch, а все же переход к адресам, поэтому это будет шитый код, и он намного более компактен чем обычный.

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

У них тоже прекрасная плотность, и даже бывает еще выше, за счет всяких битов которые например определяют сохранять ли аргумент, и за счет очень малого числа инструкций сами команды тоже маленькие, вот полный список инструкций которые реализует ga144 (33 штуки) https://colorforth.github.io/inst.htm

Про форт-процессора RTX2010 написано на википедии:

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

Было бы странно, если бы форт-машины были плохо приспособлены для стекового кода.

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

Как инструкции нету, но на той же странице есть код для реализации:

/mod for begin over over . + -if drop 2* swap next ; then over or or - 2* - next ;
И умножение с 36 битами результата.

Мне еще нравится код реализации cos/sin https://mschuldt.github.io/www.colorforth.com/cos.jpg

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

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

почему-то не видно ни одной «высокоуровневой концепции» среди этих 33 команд. что они имеют ввиду?

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

Потому что процитировал я описание RTX2010, а команды ты смотришь от процессора из GreenArray. RTX2010 для полетов в космос сделан, думаю достаточно серьезно. Еще Эльбрус-2 был стековый.

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

Ты зашел в тред о лиспе что бы обсуждать мейнстримные технологии?

Кстати, это все вполне себе мейнстримные технологии, я недавно обнаружил что свежей версии Nvidia CUDA используются биндинги к CUBLAS на Fortran, а Forth младше его на десятилетие.

Nvidia даже NVFortran компилятор запилила по такому поводу.

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

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

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

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

Как TeX переписали с Паскаля на Си.

а потом еще раз зачем-то переписали на Rust в модно-молодежном tectonic , впрочем еще была ссылка на Java реализацию

вообще, на мой взгляд, лучше бы переписали на Ада или Modula-2 или Oberon-2 или Active Oberon, или вообще какой-нибудь каноничный Algol-68

и больше не трогали своими кривыми ручонками

ну или на D2, например, можно было бы сделать на PEG грамматиках CTFE парсер транслирующий этот Pascal-H в каноничный D2

вообще, Rust реализация частично имеет смысл: например, он более модульный как дистр; XeTeX из коробки и Unicode; можно было бы еще AST-макросы сделать для трансляции в каноничный Rust

что характерно, что изначальная реализация на Паскале Pascal-H тоже не была первой. первой была на SAIL.

а этот Pascal-H не совсем каноничный, оттуда и некоторые заморочки в реализациях транслятора (хотя, как мы видим, обычный ISO Pascal в gpc или P2,P4,P5,P6 от него не сильно отличается, да и под fpc патчи с gpc написали таки)

кстати, TinyTex неплохой дистрибутив, более компактный чем texlive, например.

вообще, на мой взгляд, литературно-грамотный подход как раз облегчает это бесконечное переписывание с языка X на язык Y. словно память переводов типа Omega-T: когда есть одна наглядно откомментированная реализация, перевести ее на другой ЯП – просто дело техники, годится даже буквальный подстрочный перевод, а не идеоматический.

впрочем, с troff наверное даже проще: начали с runoff на BCPL и PL1 реализациях, затем переписали на каноничный С, уникодный в Plan9 C и groff, ну и более-менее фичастый heirloom troff в плане алгоритма переноса строк из TeX и нормальной поддержки TTF/OTF шрифтов и уникода.

а потом еще в OpenBSD mdoc придумали которым этот troff в духе классических манов писать еще проще.

то есть, тут тоже нужно брать что-то типа AsciiDoc подобное и в этом направлении упрощать (но не в ущерб функциональности).

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

алгол 68 задумывался как «ортогональный» в смысле используемых концепций язык программирования

но даже он например требует мусоросборщика ибо HEAP классы памяти в реализации lisp и консов в примерах к algol68-g

ортогональный например асм 68k, PDP-11 в смысле любой регистр а не выделенный в используемых опкодах

в этом смысле все эти паскали и модулы ады и обероны потомки алгол W а также сишки лимбы гошки bcpl-ки упрощенные потомки того самого алгол 68 изначального, гораздо более обкоцанные концептуально чем прародитель

ща раскуриваюсь btree

про мумпсы почитай, например Kevin O’Kane про libmumps.cpp реализацию.

и кодасил и кобол и сетевую модель данных, лол.

мне и форты не иконы

фактор с образом и комбинаторами в этом смысле более конкатенативен, Point-free и изкаробочен.

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

в этом смысле более ортогональный даже не алгол 68 ибо HEAP, сборщик мусора, рантайм в виде standard prelude и прагматы и каналы – а даже более ортогонален Оккам и CSP Хоара и PAR/SEQ/CHAN вот это все.

хотя и PAR, и SEQ и даже channels появились изначально в том же самом Algol только не всегда сразу.

ну а акторы хьюитта еще ортогональнее.

first class something где something более ортогональное чем, а сам язык выступает такой алгеброй носителем этих something-объектов.

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

еще есть APL, J, Joy, K (Kona), Q – где есть first class матрицы, комбинаторы: глаголы, прилагательные и наречия

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

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

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

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

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

ваще косвенный шитый это по сути эмуляция проца

ибо opcode == номер в таблице адресов - а возможный самой командой парсинг байткода - делает cisc :)

когда памяти НЕТ любоя(ну как O(f) :) ) прога косвенно шита

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

ващет у Мура массовая паралельность на XX лет раньше

у него количество транзисторов на ядро исполнения подобно LS-30, PDP-1 (6) т.е чел упарывался в реальную зелёную энергию - до 7к транзисторов на ядро

как результат его процы на нужных ему задачах были очень фефе ктивны


They make 144-core arrayForth chips with up to 0.65 watts of power consumption and 96 billion operations per second. Each core has built-in RAM and the ability to communicate with adjacent cores.

Also, GreenArrays told me that they don't make open source hardware because they «don't see the point in doing so.» Is it possible to convince GreenArrays to make their chips libre?

https://www.greenarraychips.com/index.html
qulinxao3 ★☆
()
Последнее исправление: qulinxao3 (всего исправлений: 2)
Ответ на: комментарий от anonymous

прст в Виртовской КНИГЕ

в модула редакции(+-1986) появилась реализация B-tree в его учебнике

прикол в том что SQL - ну вот этот вот ORM «импенданс» вырос из запаздывания (ибо не так низковесяче) прикручивания АДТ в поля кортежей в n-отношениях у наиболее экономически успешных rdbms

ща лежу в сторону postresql - в продолжение к Навигатору Бахмана переоткрываю http://rkka21.ru/docs/turing-award/ec1981e.pdf

ну и Грей(транз акции) и 2014 кирпричекладущий Миша

забавно что

структуры [ХРАНЕНИЯ] данных

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

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

дело в хохме когда вместо одно формулу

y=x0+x1*t+x2*(t**2)/2 .......

гойворят про y=x0

затем про равномерное

и заканчивают на равноускореном

одна из реальных причин отделивших «ООП» от структурного программирования в части структур данных

«оживление» структуры при распределённости исполнения системы на на нескольких узлах(ибо быстрее) - таже Симула именно моделировала распределённость

а до «первоклашек» испорченотелефольнулось в триединство «Наследование\Сокрытие\Полиморфизм»

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

Еще там ядра работают асинхронно относительно друг друга, не от единого такта.

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

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

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

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

вот щи

у тех процов (по тех сложности) не было даже общего тактирования - т/е оно не для однородно-параллельного

оно для возможности не эмулировать n-независимых потоков - а раскидать каждый поток на по возможности свой исполнитель - крч sse перекраска регистров но на «файле» исполнителей

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

так то реальность конкурентно это «мы» приучены её seq в один поток

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

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

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