LINUX.ORG.RU

присвоение внутри if

 


0

3

Зачем в языках программирования, например с Си и прочих, которые унаследовали его синтаксис есть возможность написать if (a=b). Вернет же всегда присвоение истину. Можете привести пример зачем это нужно? Попросили объяснить почему компилятор сам не понимает когда надо == а когда =. Не смог.

Перемещено JB из talks

Ответ на: комментарий от anonymous
[ 3500 fib ] time
Running time: 0.002768274 seconds
...
207130242203026275341619953729934146420769196734460097332608824722385384129249316079769734334045194449765931169332916009997704931531881944873913582286951513424682248770868964253684228104382689660431435922397519756497357499967505758679688646649075302803539077528386858224498222588856280163988716395494385174391839960163039177209350627464390126710780519800906469209323422419340370206160685029942665147699080894547312128772252056873619870227805192104251242507890220628181380481902079219434109323696121231264625722768733484440412902313033879037929246974105582008193813127877888969955929338924710176760096431782662127393614942208069808665358891583772406001030408459587892001012185206668209362160782987676392635512259975382189797347146626
quantum-troll ★★★★★
()
Ответ на: комментарий от anonymous
(de make-enum @
     (let @Enum (make (for (I . X) (rest) (link (cons X I))))
	(fill '((X) (cdr (assoc X '@Enum))))))
(setq color (make-enum 'red 'green 'blue ))
-> ((X) (cdr (assoc X '((red . 1) (green . 2) (blue . 3)))))
: (color 'blue)
-> 3
: (color 'green)
-> 2

Так пойдет?

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

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

Но, всё-таки, стоит отметить, что возможности метапрограммирования PicoLisp, так или иначе, позволяют это сделать.

Приведу тогда для сравнения новый вариант моего решения:

(defmacro defenum [name & colors]
  `(defmacro ~name [param#]
     (cl-case param#
       ~@(map-indexed (fn [index color]
                        `(~color ~index))
                      colors))))


Здесь cl-case - это case в стиле CL со скобками, в defmacro им удобнее пользоваться. map-indexed - понятно, обычный map (mapcar) только с индексом, в Clojure из коробки. Обе фичи утилитные, используются повсюду.

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

Кстати, лиспы уже умеют maybe?

maybe

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

s/colors/elements
s/color/element

так вот вы какие, s-expressions

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

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

Улучшать можно до бесконечности. Рекламировалось отсутствие разницы для описания функции и «макроса», а также довольно удобный набор инструментов. Именно благодаря этому, первый же вариант оказался ровно вдвое короче, чем твой улучшенный. Легкость в понимании неподготовленным читателем никто не обещал. :-)

Стоит заметить, что enum как, впрочем, и массивы, автор picolisp тоже отправил на помойку. Поэтому наше упражнение имеет только чисто академический интерес.

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

Поскольку алгоритм ОЧЕНЬ не оптимален

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

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

Кстати, а что показывает здесь с-версия?

Не очень оптимальная версия, но всё же:

#include <stdio.h>
#include <stdlib.h>

#include <gmp.h>

void fibo(mpz_t *r, int n)
{
    mpz_t a, b;
    mpz_init(a);
    mpz_init(b);
    mpz_set_ui(b, 1);

    for (int i = 0; i < n; ++i) {
        mpz_add(*r, a, b);
        mpz_set(a, b);
        mpz_set(b, *r);
    }

    mpz_clear(a);
    mpz_clear(b);
}

int main(int argc, char **argv)
{
    mpz_t r;
    mpz_init(r);
    fibo(&r, atoi(argv[1]));
    gmp_printf("%Zd\n", r);
    mpz_clear(r);
}
$ time ./fibo-gcc 3500    
207130242203026275341619953729934146420769196734460097332608824722385384129249316079769734334045194449765931169332916009997704931531881944873913582286951513424682248770868964253684228104382689660431435922397519756497357499967505758679688646649075302803539077528386858224498222588856280163988716395494385174391839960163039177209350627464390126710780519800906469209323422419340370206160685029942665147699080894547312128772252056873619870227805192104251242507890220628181380481902079219434109323696121231264625722768733484440412902313033879037929246974105582008193813127877888969955929338924710176760096431782662127393614942208069808665358891583772406001030408459587892001012185206668209362160782987676392635512259975382189797347146626
./fibo-gcc 3500  0.00s user 0.00s system 54% cpu 0.002 total
quasimoto ★★★★
()
Ответ на: комментарий от quantum-troll

Спасибо, очень впечетляет.

А почему вычисление 3500 fib происходит намного быстрее чем 3400?

Running time: 0.003441205 seconds   3400 fib
Running time: 0.002768274 seconds   3500 fib

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

Рекламировалось отсутствие разницы для описания функции и «макроса»

Ну-да, так и тянется рука aif с defenum в mapcar подставить, от функций прям не отличишь.

Отлаживаются макросы очень прозрачно через macroexpand.

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

Ну-ну, переводы строк расставь. :) Изначально я так и делал, просто не хотел вводить лишние сущности для новичков.

Поэтому наше упражнение имеет только чисто академический интерес.

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

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

Спасибо, но алгоритм не тот. В той реализации, что была тобой предложена был не цикл, а просто чудовищная по неэффективности рекурсивная функция. Которую я превратил в более-менее вменяемую с помощью маленького изменения средствами САМОГО ЯЗЫКА.

Пожалуйста, используй тот же самый монстрообразный алгоритм для сравнения, что и я. И еще было бы неплохо узнать параметры железа и время для 35 на базовом алгоритме.

Кстати разница между 0.002 и 0.03 не два-три порядка

anonymous
()

Вернет же всегда присвоение истину.

вернет вообще то а, если я не ошибаюсь.

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

Отлаживаются макросы очень прозрачно через macroexpand.

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

страшилище с setq и кавычками получилось

О вкусах не спорят, не нравится setq используй let Кавычки убрать - дело не хитрое

оно и не взлетит даже

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

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

А алгоритм какой использовался? Та ужасная рекурсия с мемоизацией или банальный цикл в стиле quasimoto?

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

точку останова добавить

Точки останова - это дурной тон в любом языке.

Или что там с пошаговым разворачиванием сложного макроса?

macroexpand-1

О вкусах не спорят, не нравится setq используй let Кавычки убрать - дело не хитрое

Сделай. Тем более, что в условие было.

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

От языка это зависит. В defmacro ты просто говришь, как новую конструкцию перевести в набор уже существующих. Всё. Проще некуда.

Посмотри defenum: «возьми уже существующий case и раскрой туда элементы с индексами».

Ты же так не можешь, у тебя только функции, надо мудрить. Для eDSL это не годится.

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

Спасибо, но алгоритм не тот.

Как я строил предложения - сравниваю неэффективную фибоначи (разница - порядок-два, в том посте я так и написал), замечаю, что эффективная фибоначи до 4-6 порядка аргумента должна выполняться за время порядка миллисекунд (~0.001s, если в PicoLisp нельзя обсчитать (fibo 10000), (fibo 100000) или (fibo 1000000) на средней машине за такое время, то что-то не так), привожу пример такой «немножко эффективной» фибоначи на си (твой вопрос про си, как я понял, содержал намёк на то что в стандартном си числа фиксированной точности).

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

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

Мне это не интересно.

Простейшую фибоначи я привёл в пример не для того чтобы потом её несколько страниц обсуждать. Посыл был в том, что вот мы берём определение функции использующее [не хвостово-рекурсивные] вызовы функций и арифметику, я ожидаю что в языке с энергичной стратегией вычисления вызовы функций будут работать через JMP/CALL, передавать аргументы через стек/регистры, if-подобные конструкции и фиксированная арифметика тоже будет ложится на соответствующие инструкции. Поэтому в любом компилируемом языке что фибоначи, что любой другой примитив использующий вызовы функций, рекурсию и т.п. будет работать за время одного порядка (да и по памяти тоже). В PicoLisp это не так - обсуждать что-то ещё уже не интересно, потому что даже такие простые вещи не перекладываются на машинный код так как этого можно ожидать.

Впрочем, если ниша языка - лёгкая переносимая скриптота, то всё ок. Хотя, даже тут можно потребовать, чтобы интерпретатор использовал промежуточный байткод (как CLisp, ECL, Lua, например). JIT не требую, его нужно на каждой архитектуре снова и снова писать (хотя, LuaJIT это не мешает, и потом, есть же LLVM, и под ARM тоже).

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

Впрочем, если ниша языка - лёгкая переносимая скриптота, то всё ок.

/me не знает ничего о PicoLisp :) Может там байткод под капотом?

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

Автор picolisp утверждает, что на некоторых задачах picolisp сравним по скорости выполнения с с-кодом, на других отстает, но разница 2-3 раза.

Одна бабк^W^WОдин человек сказал, что в среднем программы на хаскеле пишутся в 10 раз быстрее чем программы на си и при этом работают в 10 раз медленнее и памяти потребляют в 10 раз больше чем программы на си, программы на хаскеле с низкоуровневыми оптимизациями при этом пишутся в 2 раза медленнее и работают в 2 раза медленнее чем программы на си (с этим можно не соглашаться). Это при том, что GHC это оптимизирующий компилятор. И тут оказывается, что PicoLisp, являющийся интерпретатором без байткода, обеспечивает производительность 1.0 - 3.0 по сравнению с plain C.

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

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

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

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

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

(de fibo(N)
     (let (A 0 B 1 R 0)
	(do N
	   (setq R (+ A B)
	      A B
	      B R))))
вот время выполнения на моем стареньком лаптопе (32-bit)
                    3500    10000   100000  1000000
C                 0.004    0.10       0.194     25.066
PicoLisp       0.009    0.024     1.891   210.655
Должен заметить, что 64 реализация работает с длинными цифрами намного лучше, в том числе и за счет отказа от тяжеловесного c-компилятор для сборки интерпретатора. Кроме того, данная задача не относится к наиболее сильным сторонам языка.

То есть интерпретируемый язык общего назначения смог в одной и 4 попыток в 5 раз обогнать узкоспециализированную с-библиотеку а в остельных он был в 2-8 раз медленне. Ни о каких 2-3 порядка речь не идет.

если ниша языка - лёгкая переносимая скриптота

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

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

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

Тут не кривой алгоритм, тут просто алгоритм. С тем же успехом можно было взять абсолютно бессмысленную тестовую функцию (не факториал, не фибоначи, в test suite компиляторов полно таких функций) в которой есть вызовы функций, рекурсия, какие-то типичные специальные формы, арифметика, и сравнить как работает такая функция в тех языках в которых её можно написать. Почему в PicoLisp она работает медленно? В остальных языках того же уровня она работает примерно одинаково. То есть где-то в SBCL

(defun bad-fibo (n)
  (if (> 2 n)
      n
      (+ (bad-fibo (1- n)) (bad-fibo (- n 2)))))

будет гораздо лучше. Как и где-то в GHC, GCC (c gmp) или LLVM (с каким-нибудь фронтендом). Это вопрос к реализации, на самом деле, и ответ в том, что та просто интерпретирует исходный код. C другой стороны, компилятор утяжеляет реализацию и делает её менее переносимой, это да.

То есть интерпретируемый язык общего назначения смог в одной и 4 попыток в 5 раз обогнать узкоспециализированную с-библиотеку а в остельных он был в 2-8 раз медленне. Ни о каких 2-3 порядка речь не идет.

Да, вот бы ещё picolisp был тут, чтобы о порядках говорить, но если оставить числодробилки в стороне, то вопрос в том что является теми фичами которые это (один случай из пяти) позволяют. Традиционно в лиспе (и тех языках которые явно или косвенно переняли некоторые возможности лиспа) это, во-первых, возможность легко создавать динамические данные и не собирать их (доверить уборку GC) и, во-вторых, функции высшего порядка, позволяющие писать более общие функции и упрощать структуру приложения. То есть, одна фича которая позволяет чего-то _не_ делать и другая, которая позволяет что-то _делать_. Какие ещё есть фичи в PicoLisp которые позволяют _делать_ то, что невозможно или сложно в других языках (про GC и HOF уже сказали, этого где только нет)? Автоматическая мемоизация (тот cache)? Например, в Эрланге или GHC это лёгкая конкурентность. В CL - пакеты, рестарты, код=данные и макросы, обновляемый образ и REPL. В GHC это модули, система типов (позволяет _не_ делать глупых проверок типов в рантайме, что позволяет _делать_ - типы общего вида (параметрические, обобщённые ADT) и выстраивать типо- (data) ориентированную структуру приложения), ленивые данные, лёгкая конкурентность, STM.

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

http://picolisp.com/5000/!wiki?ideasPage - это?

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

один случай из пяти

Не так понял фразу, ну да ладно.

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

То есть интерпретируемый язык общего назначения смог в одной и 4 попыток в 5 раз обогнать узкоспециализированную с-библиотеку

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

Так что есть шанс оторвать кусок, как в области серверов приложений

без тредов/многопоточности/конкурентности? И мне, и мне такой травы!..

так и на встроенной технике

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

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

То есть где-то в SBCL будет гораздо лучше

Да, это правда. Разница на 32-битной реализации более чем на порядок: 0.44 (с (declare (optimize speed))) против 6.4.

Традиционно в лиспе (и тех языках которые явно или косвенно переняли некоторые возможности лиспа) это, во-первых, возможность легко создавать динамические данные и не собирать их (доверить уборку GC) и, во-вторых, функции высшего порядка, позволяющие писать более общие функции и упрощать структуру приложения. То есть, одна фича которая позволяет чего-то _не_ делать и другая, которая позволяет что-то _делать_. Какие ещё есть фичи в PicoLisp которые позволяют _делать_ то, что невозможно или сложно в других языках

Подробно об отличиях: http://www.software-lab.de/doc/faq.html#advantages

Лично мне понравились:

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

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

http://picolisp.com/5000/!wiki?ideasPage - это?

Да.

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

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

Если можно поподробнее, о том как настраивать уже собранную gmp библиотеку. Если имеется ввиду ключик -O2 при сборке то, он уже использовался.

без тредов/многопоточности/конкурентности? И мне, и мне такой травы!..

треды == многопоточность != конкурентность Реализация конкурентного выполнения с помощью процессов не настолько много проигрывает тредам по быстродействию, чтобы имело смысл для языка сверхлегкого класса типа picolisp иметь с ними дело и мучатся с проблемами, которые неизбежно с ними связанны (gc, защита памяти, синхронизация и т.д.). Преимущество пиколиспа в его простоте и скорости разработки. Работу, которую должна делать толпа ява кодеров можно сделать и одному. Высокое быстродействие нужно не каждому серверу приложений.

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

Лично мне понравились

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

There are only three data types: Numbers, symbols and lists

There is only one symbolic data type, no distinction (confusion) between symbols, strings, variables, special variables and identifiers.

Без чисел фиксированной точности, чисел разной битности, больших чисел, плавающих чисел IEEE 754, рациональных чисел, комплексных чисел, массивов, строк, ссылок, хэш таблиц, структур и объединений определяемых пользователем будет тяжко. ИМХО, это упрощение которое, в конечном итоге, вредит удобству использования.

Например, как быть с коллекциями с O(1) доступом к n-ому элементу?

Вообще, похоже на то что описывал Paul Graham в одной своей статье, такой yet упрощенный LISP 1.5 (Graham ещё числа не вводил, вон, в теории множеств вообще одним {} обходятся). Интерпретатор. Плюс немного сахара и функций для списков (такие функции в любом лиспе можно написать), плюс пролог (встроенный пролог можно в любом лиспе оформить), плюс мемоизация (тоже оформляется библиотечно).

Реализация конкурентного выполнения с помощью процессов не настолько много проигрывает тредам по быстродействию

Joe Armstrong давал такое определение конкурентности - если в языке можно легко создавать миллионы фиктивных и сотни тысяч реальных процессов, то язык поддерживает конкурентность, если нет - то нет. Тут «процесс» != процесс ОС, это процесс VM, в Erlang он так и называется, в GHC называют тредом. Основная идея в том, что процесс VM может быть лёгким если его контекст в основном вычислительный, а IPC и IO осуществляются асинхронными сообщениями, то есть контекст IO перенесён в отдельный процесс (IO manager) в котором выполняется всё event based мультиплексирование, а временной контекст перенесён в процесс time managerа.

и мучатся с проблемами, которые неизбежно с ними связанны (gc, защита памяти, синхронизация и т.д.).

STM, персистентность данных, синхронные/асинхронные сообщения, копирование вместо разделения данных. GC тоже упрощается в случае только персистентных данных. Я к тому, что лёгкая конкурентность, возможная в случае персистентных данных, как раз может считаться киллер фичей, хотя она и требует утяжеления VM.

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

Высокое быстродействие нужно не каждому серверу приложений.

Ему нужна масштабируемость. Форкать процесс ОС на каждого клиента это не Ъ.

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

Если можно поподробнее, о том как настраивать уже собранную gmp библиотеку.

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

Реализация конкурентного выполнения с помощью процессов не настолько много проигрывает тредам по быстродействию

О_о это полностью взаимозаменяемые способы организации параллельных вычислений?

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

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

Я уже не понимаю о чём мы спорим. Пиколисп - очень «нишевый» продукт. Имеет ли право на жизнь? Да! Но надо помнить о его ограничениях и не «натягивать гандон на глобус».

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

Без чисел фиксированной точности, ... ,больших чисел

Это есть. Фиксированная точность сделана на основании больших чисел.

строк

Есть

структур и объединений определяемых пользователем

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

чисел разной битности, плавающих чисел IEEE 754, рациональных чисел, комплексных чисел,

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

массивов, хэш таблиц
Например, как быть с коллекциями с O(1) доступом к n-ому элементу?

Аргументация у автора была примерно такая: при маленьком колличестве элементов скорость у массива и списка примерно одинаковая, при среднем - бинарное дерево не намного хуже. Для огромных массивов - есть файлы и/или база данных. Т.е. можно обойтись -> значит не надо.

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

То же самое касается хэш таблиц.

ссылок

зачем это тащить в лисп?

будет тяжко.

Зависит от задачи. Есть довольно много вещей где это не надо.

Вообще, похоже на то что описывал Paul Graham в одной своей ...

Все лиспы в чем-то похожы и то, что есть в одном, можно (при наличии соответствующих ресурсов) перенести в другие. Просто это здесь уже есть.

По поводу конкурентности. Я не упомянул довольно простую возможность использования методов основывающихся на select вызове. Используя это, совместно со встроенной в язык поддержкой конечных автоматов, можно организовать «параллельные» вычисления в одном процессе. Хотя все это загрузить второй процессор, к сожалению, не может.

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

Если можно поподробнее, о том как настраивать уже собранную gmp библиотеку.

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

Ok. Спасибо.

О_о это полностью взаимозаменяемые способы организации параллельных вычислений?

Довольно близкие, но не тождественные.

Я уже не понимаю о чём мы спорим

Да мы и не спорим. Обмениваемся информацией и общаемся на интересные друг другу темы.

Но надо помнить о его ограничениях и не «натягивать гандон на глобус».

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

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

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

Имеется ввиду record и union.

зачем это тащить в лисп?

Чтобы было же. Хотя это наименьшая необходимость. В CL явные ссылки только в реализациях в FFI.

Я не упомянул довольно простую возможность использования методов основывающихся на select вызове.

Ну да, select/poll/epoll/kqueue libevent/twisted/EventMachine/node.js, это имеет некое отношение к лёгкой конкурентности в которой мультиплексирование делается в IO manager. В любом языке такое делается средствами FFI.

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

Имеется ввиду record и union.

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

Реинтерпретация памяти даже в С считается опасным хаком, который стоит прятать от глаз слабонервных пользователей :-)

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

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

Структуры и статические массивы это непрерывные (монолитные) структуры которые заведомо занимают _определённое_ количество байт в памяти, кроме того, они часто целиком попадают в кэш CPU, в отличии от разрозненных cons-ов, постоянной уборкой и упаковкой которых и занимается GC. Ну и у структур доступ к полю тоже O(1), плюс, не нужно хранить символическое имя поля (как это нужно делать если кодировать структуры списками, вроде (:a 2 :b 2 :c 3)).

Реинтерпретация памяти даже в С считается опасным хаком

А это тут при чём?

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

они часто целиком попадают в кэш CPU

Т.е. сама железка устроена так, что преимущество будет у монолитных массивов и структур. RAM память не совсем `R`AM (разница в порядок), разные cons-ы, вероятно, не равны между собой (с точки зрения локальности), тогда как элементы массивов и поля структур, вероятно, равны.

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

_определённое_ количество байт в памяти

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

Ну и у структур доступ к полю тоже O(1), плюс, не нужно хранить символическое имя поля (как это нужно делать если кодировать структуры списками, вроде (:a 2 :b 2 :c 3)).

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

Реинтерпретация памяти даже в С считается опасным хаком

А это тут при чём?

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

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

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

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

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

Свобода в интерпретации аргументов ведёт к необходимости писать внятную документацию к функциям.

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

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

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

Часть информации (какой из аргументов интерпретируется, а какой передается как есть, и сколько из всего) видно из декларации функции.

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

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

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

Свобода в интерпретации аргументов ведёт к необходимости писать внятную документацию к функциям.

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

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

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

Почему не известно? Правила однозначны и описанны в документации

(de foo (X Y))

Два вычисляемых аргумента

(de foo @)

Переменное число вычисляемых аргументов

(de foo (X Y . @))

Переменное число вычисляемых аргументов, первые два имеют имена

(de foo X))

переменное число невычисляемых аргументов, передаются в виде списка с именем X

(de foo (X Y . Z))

Два вычисляемых аргумента и переменное число невычисляемых аргументов, передаются в виде списка с именем Z

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

Почему не известно?

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

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

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

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

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

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

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

Ну так я и спрашиваю - зачем нужны такие значительные усложнения семантики? Почему вместо простого, гибкого и эффективного решения выбрали сложное, негибкое и неэффективное?

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

Ну так я и спрашиваю - зачем нужны такие значительные усложнения семантики? Почему вместо простого, гибкого и эффективного решения выбрали сложное, негибкое и неэффективное?

сложное,

В чем сложность то? Если просто сравнить количество документации, которое нужно прочитать, чтобы правильно описывать функции в picolisp и сравнить с описанием функций и макросов в CL, то станет очевидным прямо противоположное.

негибкое

что имеется ввиду?

неэффективное

опять будем сравнивать производительность интерпетатора размером в 200К и компиляторов размeром в 20М на кривом алгоритме далеком от основной области применения языка?

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

В чем сложность то?

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

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

В каком-нибудь CL и функций банально больше - вот и доки пропорционально больше. Если построить доки аналогично пиколиспу, то это будет просто описание двух форм - defun и defmacro, не больше чем в пиколиспе. То есть сложность документации совпадает. А вот сам код в общелиспе будет уже на порядок проще, т.к. семантика более четкая и ясная.

что имеется ввиду?

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

опять будем сравнивать производительность интерпетатора размером в 200К и компиляторов размeром в 20М на кривом алгоритме далеком от основной области применения языка?

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

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

В чем сложность то?

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

Пожалуй, я соглашусь в том, что понимать код, в особенности написанный человеком, который глубоко нырнул в тему, довольно сложно. Нужно хорошо понимать, что делает каждая функция и, то и дело, заглядывать в документацию. Простота изучения не была целью дизайна. Цель - минимально необходимый набор (сложных) инструментов, позволяющий профи эффектно излагать свои мысли. Как результат, конечная программа получается простой и прозрачной (для подготовленного читателя). Это очень наглядно видно на http://rosettacode.org/wiki/Rosetta_Code. Те задачи, что можно решать на нем получаются значительно короче, чем на том же CL, особенно если обратить внимание, что picolisp не использует для этого сторонние библиотеки.

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

С моей точки зрения, они практически взаимозаменяемы. Я, наверное, что-то пропустил.

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

Аргументов много и размер - всего лишь очень приятный бонус. У нормальных лиспов - очень разная скорость. С одной стороны sbcl c другой abcl c ecl. Пиколисп по скорости будет где-то посередине. Скорость пока что для меня никогда не была ограничением, хотя часто использую очень скромную технику.

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

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

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