>Гм. А зачем это знать, если алгоритм все равно работает по последовательности? Интересно знать, скорее, тип содержимого контейнера.
А компилятор CL? Массивы, списки и хэши физически по-разному организованы. И физически по ним перемещаться надо по-разному. Следовательно, на каком-то этапе все-равно необходимо перейти на реализацию map, характерную для даного типа данных. Если бы ты знал тип данных заранее, то можно было бы в зависимости от типа подставлять необходимую реализацию. А так ты напишешь (defun foo+1 (seq) (super-map #'1+ seq)), например. Ну? И какой тут тип seq? Да любой может быть. Поэтому должна будет быть введена диспечеризация, и конкретная реализация на низком уровне будет выбираться уже в рантайме. Это плохо. Если же я указываю (defun foo+1 (seq) (maphash #'(lambda...) seq)), то тут явно указано, что seq ожидается, как хэш-таблица. При компиляции сразу выбирается необходимая реализация map*
> А компилятор CL? Массивы, списки и хэши физически по-разному организованы. И физически по ним перемещаться надо по-разному. Следовательно, на каком-то этапе все-равно необходимо перейти на реализацию map, характерную для даного типа данных.
Угу. Поэтому в таких задачах рулит явная типизация и <перегрузка|шаблонизация>. Тогда все делается в момент компиляции.
Никто, собственно не возражает, что CL работает и имеет право на жизнь, мы пытаемся выбить из головы некоторых мысли о "превосходстве Lisp на порядок" над "императивными быдлонаречиями".
Нету такого, Lisp - просто еще один (хороший) язык, в чем-то лучше других, в чем-то хуже.
>Лет 15-16 назад. Сначала по книгам, потом на писишках. но под ДОС. >Была такая вещь xlisp (?). Впрочем, длилось это недолго - надо было >учиться и работать
Знаю я xlisp и его прозводные, например xlispstat. Довольно интересный Лисп, рассчеты на нем статистические делал, удобная штука довольно таки. Там операции всякие тяжелые на Си реализованы, все остальное в байт коде сидит.
>Сходи на shotout и сравни SBCL с лидерами. До D и даже C++ ему >далеко. Окамлю он поменьше проигрывает, но, имхо, потому, что >компилятор более зрелый и вылизанный - его уж 20 лет пишут, блин.
Ну да, если писать программы к в shootout,не обращая внимания на стоны оптимизатора, используя тормозные структуры данных и виртуальные вызовы, то ему точно никогда не приблизиться. Возьмите там любую прогу на SCBL и оптимизируйте, разница в скорости существенно сократится.
Был тут они ray-tracer, так после оптимизации он оптимизированный GCC таки сделал, за счет того, что при малом количестве типов, typecase работает быстрее, чем универсальный виртуальный вызов в С++, ну и как в C++ заточить виртуальные вызовы под определенную статистику, чтобы на наиболее частые вызовы тратилось минимум времени ?
>Также в лиспе нельзя доопределить новый численный тип и перегрузить >#'+, #'*, ... для него. К примеру, если мне нужны кватернионы, то >складывать их придется уже не с помощью #'+.
Да можно всякими способами, причем перегруженный + будет действовать только в пределах нужного пакета:
> Был тут они ray-tracer, так после оптимизации он оптимизированный GCC таки сделал
Фиг-то там! g++ там сделал всех, к нему вплотную приблизились Stalin (Scheme) и ocamlopt (OCaml). SBCL жестоко слил всем, кроме жаббы, а по количеству строк кода слил вообще всем.
>Фиг-то там! g++ там сделал всех, к нему вплотную приблизились >Stalin (Scheme) и ocamlopt (OCaml). SBCL жестоко слил всем, кроме >жаббы, а по количеству строк кода слил вообще всем.
Мож мы про разные трэйсеры говорим. Та история началась, когда один зашел на comp.lang.lisp и давай плакаться, что Лисп мол медленный, вот мол трэйсер на С++ и вот под SBCL (начальный алгоритм для SBCL действительно был раз в 20 тормознее g++). Ну всем миром подкрутили трэйсер для SBCL. В итоге g++ отдохнул культурно, процентов на 10-15. Я еще дописал пару макросов, чтобы можно было любое количество фигур добавлять и не говорили, что мол это оптимизировано руками под две фигуры. В С++ виртуальные вызовы дорогие однако :-)
Можно также извратиться со списками типов как в Александреску, но выглядеть это будет всяко ужасно.
---- Блин, где LOR взял такую отвратную каптчу, нихрена на ней не разберешь.
>Фиг-то там! g++ там сделал всех, к нему вплотную приблизились >Stalin (Scheme) и ocamlopt (OCaml). SBCL жестоко слил всем, кроме >жаббы, а по количеству строк кода слил вообще всем.
Сейчас глянул по ссылке. Тот самый трэйсер это и есть. Так что g++ ничего не светит ;-) Под виндой надо проверить на VC++ 8.0 и SBCL под винду уже пашет во всю.
Материалы по ссылке говорят об обратном. Так что либо показывайте ваш докрученный всем миром рейтрейсер на Лиспе, либо засчитываем вам минус одно очко. :)
> Смотреть третью колонку. Во _всех_ бенчмарках питоньи программы короче.
ИМХО хня какаято. открыл исходник де больше всего разницы. Лисповая прого чёто делает мне непонятное а в питоньей груда каментоф и всево две незакомменчетые строки
import sys, itertools
print sum(itertools.imap(int, sys.stdin))
Это так понимать чё питонья прого становицо короче лисповой, если все 500 с малым гаком обектов убрать из её в отдельную либу и закрыть на их глаза, подобно тому как это пытались сделать в этом топе?
> Это так понимать чё питонья прого становицо короче лисповой, если все 500 с малым гаком обектов убрать из её в отдельную либу и закрыть на их глаза, подобно тому как это пытались сделать в этом топе?
В питоне есть понятие пространства имён. itertools входит в состав стандартной библиотеки. import itertools это просто подключение части стандартных возможностей языка.
Хуже того, в данном случае, это можно написать как
>Материалы по ссылке говорят об обратном. Так что либо показывайте >ваш докрученный всем миром рейтрейсер на Лиспе, либо засчитываем >вам минус одно очко. :)
Покажу я заоптимизированный трэйсер, все поймут, что Лисп не медленный и начнут все писать на Лиспе, тогда как я буду зарабатывать на нем ?
> Это так понимать чё питонья прого становицо короче лисповой, если все 500 с малым гаком обектов убрать из её в отдельную либу и закрыть на их глаза, подобно тому как это пытались сделать в этом топе?
Так и запишем - стандартная библиотека лиспа не позволяет простым способом читать числа-в-виде-строк из файла и просуммировать их?
print map {"Бугога!!!\n"} 1..1_000_000; #yes I know this wastes memory - this is purely applicative ;-)
>> Это так понимать чё питонья прого становицо короче лисповой, если все 500 с малым гаком обектов убрать из её в отдельную либу и закрыть на их глаза, подобно тому как это пытались сделать в этом топе?
> Так и запишем - стандартная библиотека лиспа не позволяет простым способом читать числа-в-виде-строк из файла и просуммировать их?
позволяет, заросто. Давай луче запишем, чё в питоньей проге нет способа зделать этого кроме как вызвать из стандартной библиотеки специально для этово случяя написатую на сях функцию, а питоноедам нечем больше похвастацо кроме стандартной либы.
> Да можно всякими способами, причем перегруженный + будет действовать только в пределах нужного пакета: <skipped>
Это мы уже обсудили. Аналогично ситуацию с map, reduce. Похоже многие лисперы тут так и не догнали о чем шла речь.
Хер с ним. Мне пришел на ум более удачный пример изъяна в CL-евской стандартной библиотеке.
Допустим мне нужно положить в hashtable ключи которые являются тройками. Равенство ключей определим покомпонентно. Т.е. ключ A равен ключу B если все элементы троек равны (например, в терминах equal). Так вот CL-евские hashtable'ы не позволяют мне эффективно иметь такие ключи, т.к. make-hash-table не дает мне указать особенные реализации хеш-функции и функции сравнения (или переопределить equal и функцию получения хеш-кода (которой нет, но которая была бы нужна)).
Частично эту задачу можно выполнить указав equalp в качестве теста hashtable и применив массив или структуру для моей тройки, но тогда получаем облом со сравнением строк и символов. Т.к. при сравнении по equalp имеем case-insensitive сравнение.
Для этой задачи подойдет equal в качестве теста и представление тройки в виде списка. Но такое представление тройки не всегда годится по производительности и/или потреблению памяти.
Даже убогая во многих отношениях реализация хешей в Java 2 platform мне такие вещи позволяет.
> Давай луче запишем, чё в питоньей проге нет способа зделать этого кроме как вызвать из стандартной библиотеки специально для этово случяя написатую на сях функцию, а питоноедам нечем больше похвастацо кроме стандартной либы.
Ну да, питон написан на С, стандартная либа на С + питон. Тогда ты прав, питоноводам (не едам, а водам) хавстаться нечем кроме ядра питона и его стандартной библиотеки, написанных на С.
Немного выше по топику ты считал достоинством лиспа то что там есть готовый контейнер для решения задачи с файлами и что тебе не надо дотачивать контейнер как в С++ или питоне. А как питон попал в аналогичную ситуацию так это уже не достоинство, а просто "из стандартной библиотеки специально для этово случяя написатую на сях функцию". Занятная манера спора.
>make-hash-table не дает мне указать особенные реализации хеш->функции и функции сравнения (или переопределить equal и функцию >получения хеш-кода (которой нет, но которая была бы нужна)).
> Допустим мне нужно положить в hashtable ключи которые являются тройками.
С десяток страниц назад я уже описывал, где конкретно это необходимо: при реализации BDD/MDD, которые используются для компактного представления булевых выражений.
На Эйфеле пришлось написать свой собственный контейнер.
> Даже убогая во многих отношениях реализация хешей в Java 2 platform мне такие вещи позволяет.
Кстати исходники хэш таблицы SBCL доступны. Если уж такой специфичный случай, когда от этого зависит производительность, то можно использовать части существующей реализации и реализовать несколько функций, чтобы можно было задавать хэш функцию и функцию сравнения, в том числе возможен шаблонный вариант как в С++, чтобы статически вкомпилировать функции, а не вызвать их посредством funcall.
Создавать таблицу потом можно будет функцией вроде make-custom-hash-table или макросом сначала определить (def hash-table myhash-table (myhashfun myequalfn)) потом для создания экземпляра вызывать make-myhash-table, а тип у нее будет тот же, остальные функции должны работать с ней как с обычной таблицей в том числе gethash, maphash, loop macro.
Если уже пишешь под Lispworks коммерческий продукт, то пофигу, ты все равно привязан к этой реализации, ведь CAPI (библиотека для GUI)тоже не входит в стандарт. Ну и потом можно уровень совместимости добавить для других реализаций, чтобы там make-hash-table выглядела так же как в Lispworks. Потом Lispworks и CAPI есть под Linux, под оффтопик, под Mac, так что вполне можно с ним жить, если производительность устраивает.
> Мне пришел на ум более удачный пример изъяна в CL-евской стандартной библиотеке...
Лучше бы ты изъяны искал в своей голове! :-Е
Стандарт не ограничивает хеш-функции в hash-tables _только_ указанными eq, eql, equal, equalp, но расширение функциональности оставляет "на совести" реализаций.
SBCL - см. *hash-table-tests* и define-hash-table-test.
Т.е. программы на лиспе у нас или короткие, но тормозные, или быстрые, но спагетти-кодинг-оптимизированные?
Спасибо, я уж лучше на плюсах. Или Eiffel/*ML какой освою.
> Давай луче запишем, чё в питоньей проге нет способа зделать этого кроме как вызвать из стандартной библиотеки специально для этово случяя написатую на сях функцию, а питоноедам нечем больше похвастацо кроме стандартной либы.
Гм. Стандартная библиотека питона написана на плюсах, и это фича такая. И это не "функции специально для этого случая", а вполне регулярно употребляемые вещи, вроде "зачитать файл в массив построчно" и "прообразовать строковое представление числа в int (man 3 atoi, да?). Эти функции необходимы едва ли не в любой юниксовой программе...
> Допустим мне нужно положить в hashtable ключи которые являются тройками.
> И как с этим обстоят дела в том же STL?
В стандарте нету хешей. В SGI-ном STL-е - есть, и в бусте есть. Чтобы иметь в них ключами тройки, достаточно определить класс тройки (увы, нету в STL-е и N-tuple готовых. В бусте, возможно, есть - мне никогда не нужно было, не смотрел), функтор hash для него (с size_t operator()(const ThreeTuple &t)), и все (ну, шаблон инстанциировать).
Т.е., с т.з. С++, нет проблем - опишите ваши типы и все поедет.
> А ты попробуй. А то с чужих слов петь - это не есть хорошо ;)
Гм. А с твоих - можно. Цитата, даже листать назад не нужно: "Позволяет. Но здесь уже не раз говорили - ввод/вывод у лиспа _медленный_. И решение в две строки (как на питоне) показало бы плохой результат."
> > Т.е. программы на лиспе у нас или короткие, но тормозные, или быстрые, но спагетти-кодинг-оптимизированные?
> Смотри не кончи :-Е
О, конструктив попер, я смотрю.
Не, вы все-таки ничего не понимаете.
Если бы мне показали идеальный язык программирования, на порядок превосходящий остальные (ну, хотя бы бьющий C++ _и_ Perl на их поле), с хорошей - открытой и кроссплатформенной - реализацией, богатой стандартной библиотекой и активным community - я бы пересел (для собственных разработок), и ходил бы с плакатом по офису агитируя коллег. На данный момент есть желание посмотреть на Ocaml/Eiffel в качестве замены C++ - но от них, как я понял, GC не отрывается, а это плохо. Должен быть выбор. D же не настолько лучше C++/Java, чтобы переучиваться, как мне показалось.
А мне предлагают (в лице CL-я) нечто странное пока - куча полусовместимых реализаций, (относительно) тормозное, (довольно таки, по сравнению с Python/Perl/ML/Haskell) многословное, со странным синтаксисом, не умеющее порождать unix-way программы, с кривыми отстающими от mainline биндингами... Ну да, есть там приятные возможности - но граблей таки больше.
А для "общего развития" я лучше что-нибудь модное изучу - Haskell там, или io - а не 30-тилетние консервы, из которых уже поуносили все интересное...
> Если бы мне показали идеальный язык программирования, на порядок превосходящий остальные (ну, хотя бы бьющий C++ _и_ Perl на их поле), с хорошей - открытой и кроссплатформенной - реализацией, богатой стандартной библиотекой и активным community - я бы пересел (для собственных разработок), и ходил бы с плакатом по офису агитируя коллег.
+1. На такую роль CL, увы, не подходит.
> На данный момент есть желание посмотреть на Ocaml/Eiffel в качестве замены C++ - но от них, как я понял, GC не отрывается, а это плохо.
Eiffel, ИМХО, слишком "традиционен". А OCaml я ниасилил :(
Он оптимизирован по скорости, а не читабельности. Вместо самописной read-int, которая и занимает бОльшую часть, можно использовать обычный read, но это будет медленнее.
> от них, как я понял, GC не отрывается, а это плохо.
Джоэль как-то сравнивал GC с автоматической коробкой передач. Более того, он считает, что именно создание приемлемых GC, а совсем не внедрение ООП совершили настоящую революцию в проектировании сложных программных комплексов. И я с ним согласен.
В общем, очень странно покупать автомобиль с автоматической коробкой, а потом жаловаться, что она оттуда не выдирается. Если не нужен GC -- оставайтесь на С++. Собственно, если бы не GC, то я бы вообще с C++ никуда бы не уползал.
И многословен. Но, в отличие от Лиспа и Питона, генерирует нормальный кроссплатформенный C-код. Для примера, мои успехи в Лиспе позволили задуматься о переносе того, что я сейчас пишу на Эйфеле, на Лисп. Однако, есть одно краевое условие: созданная утилита должна подключаться, как плагин к некому закрытому коммерческому продукту под оффтопик. Эйфель на выходе дает С-код, который несложно прикрутить, как обычную программу на С через заданный плагин интерфейс (собственно этим даже не я буду заниматься -- у нас есть специалисты по этому делу). Поэтому и не подходит Питон. По крайней мере, я не знаю, как из него сделать нечто вроде dll с заранее заданным интерфейсом на С. Более того, чтобы один и тот же код в зависимости от режима компиляции создавал или утилиту командной строки или библиотеку. Может, кто подскажет?
Насколько я понял, генерация бинарников в открытых лиспах под оффтопик -- это отдельная проблема. Но вот можно ли быстро и элегантно генерить кроссплатформенный С-код из лисповских программ? Как я понял, это тоже пока невозможно? А было бы вкусно.
> Джоэль как-то сравнивал GC с автоматической коробкой передач. Более того, он считает, что именно создание приемлемых GC, а совсем не внедрение ООП совершили настоящую революцию в проектировании сложных программных комплексов. И я с ним согласен.
Я вот тут работаю с большим программным комплексом на C++ - и ниччо. И в соседнем отделе еще один есть, на C++ on CORBA. Немножко стековой дисциплины + смартпойнтеры позволяют не так уж часто делать delete вручную, чтобы не сказать "вообще никогда".
GC - штука хорошая, но в системах массового обслуживания он периодически дает странные эффекты, особенно в своей жабьей ипостаси. Опять же, стековая дисциплина с предсказуемым временем разрушения, как в C++, позволяет автоматизировать учет не только памяти, но и других ресурсов (мутексы, файлы, сокеты, соединения с БД), причем exception-safe образом. Это не очень легко (особенно с т.з. автора библиотеки), но отнюдь не невозможно.
А parse-integer тоже тормозная ?
#def main():
# count = 0
# for line in sys.stdin.xreadlines():
# count += int(line)
# print count
#
#main()
(defun main ()
(print
(loop for int of-type integer = (parse-integer (read-line *standard-output*))
while (integerp int) sum int)))
(main)
Я не понял, должно оно для бигнумов тоже работать ?
Пардон. Привычка, блин. Не тот поток получается. Вот правильно:
(defun main ()
(print
(loop for int of-type integer = (parse-integer
(read-line *standard-input*))
while (integerp int) sum int)))
(main)