> Но статья не поможет тем, кто не собирается ничего искать/иенять.
Таким нельзя помочь
> А кто собирается - всё равно пойдёт своим путём, пусть и с поправкой на ветер.
Тот пост на RSDN ценен еще и тем, что в нем описан отказ от изобретения велосипеда. А те, кто "всё равно пойдут своим путем", могут наизобретать таких велосипдеов, что мало не покажется.
> Короче - примеры ОС (не для Лисп-машин), написанных на Лисп - в студию!
Ну какого лиха юзать высокоуровневое наречие там, где С справляецо гораздо лучше? Там разве есь необходимость в высокоуровневом? Кстати, Кроме С что ещё для осостроения юзают? Я знаю только в беосе пытались С++, причём неудачно.
>...ничего всё равно не наизобретают. Ибо бестолочи
Обычно они умные ребята, но не умеют оценивать сложность проекта, выгорают, слишком эмоционально относятся к результатам своей работы (если ее заканчивают)...
Но иногда из этого получается GCC/Linux/Python/SQLite 8)
> Я все то же самое могу и на перле делать, в синтаксисе, который мне ближе и роднее.
Всё правильно, на любом Тьюринг-полном можно, хоть на браинфаке. Кому какой синтаксис роднее - дело сугубо интимное, никто не заставляет. Это видимо твой пример сверху на перле? Извини, сразу не ответил, чёто задумался о превратностях судеб этого мира и позабыл.
Согласен, короче. Возможно даже работать будет быстрее или оперативы меньше отъест. Однако выглядит ИМХО довользо замысловато. Однако, запишем задачу о перестановках на (формализованном) человечьем языке:
совокупность из последовательностй, в которой каждый элемент - последовательность, составленная из одного из элементов исходной и набора перестановок оставшихся.
Корявая довольно фраза, и не всем сразу понятная (напишите луче кто сумеет, я сейчас изрядно не выспамшись :P), но зато практически 1:1 переводится в лисп-программу. Нет необходимости в $i, а переменные - не "хранилово данных" а символьное представление информации, т.е. их сущность ближе к математическому а не программистскому мировоззрению. Поэтому я утверждаю, что лиспологика ближе к человекологике, чем у например перла, а значит и переход от мыслей программиста к срокам кода - легче, и разница тем ощутимее чем сложнее задача.
>> Ёжики плакали, кололись, но продолжали писать на плюсах.
> Ёжики плакали, кололись, но продолжали хвалить Лисп.
Ёжики всегда будут плакать и колоцо, потому что они ёжики. Такая уж их судьба, что всё сущее служит для их истязания и огорчения. Неважно, лисп это, плюсы, виндовсь или линух, важно, что они - ёжики. Быть уколотыми и заплаканными для них - их святой долг и вечная обязаннось, modus vivendi, единственно возможное состояние, основополагающий принцип, альфа и омега, причина и оправдание их бытия, настолько же неизбежный и фатальный, как и непогрешимость для миллионов мух.
> Макры намеренно забыл? Их ты на чём будешь делать? Да и не уверен я - CLOS c MOP-ом точно на перле повторишь? CLSQL видел? И это сделаешь? (это я про readtable) И на что это всё вместе будет похоже? :)
На перле есть source filters и парсер-перл-на-перле. Т.е., в сумме, тот же самый readtable. А MOP на перле есть готовый, даже несколько, IIRC, в т.ч. и с multiple dispatch. Тока в повседневной жизни это ненужно.
> На перле есть source filters и парсер-перл-на-перле. Т.е., в сумме, тот же самый readtable.
Примочки сбоку есть почти для всех. В CL это в самом языке и в любой момент. Да и генерить списки на языке для его обработки естественнее, чем генерить на перле перловый код. Или и здесь будешь спорить? :)
> Согласен, короче. Возможно даже работать будет быстрее или оперативы меньше отъест. Однако выглядит ИМХО довользо замысловато.
Это, блин, дословный перевод той лисповой программы на Perl. Прям совсем дословный, ну и слегка Perl Golf-овый - поэтому выглядит страшно. А если декомпозицию нормально сделать, то будет вполне красиво, будет две функции, правда.
> совокупность из последовательностй, в которой каждый элемент - последовательность, составленная из одного из элементов исходной и набора перестановок оставшихся.
Угу. Именно это там и написано, на перле. А $i там нужна только по сугубо исторческим причинам - вот такой странный в перле map (он использует переменную $_, поэтому при написании вложенных map-ов приходится заводить алиас, в данном случае - $i).
И ты забыл еще "а перестановка пустого списка одна - пустой список".
Цитата со ссылки: "Хотя мож от таково кода тож ктото проблюёцо" - я среди этих "кто-то". Так писать может только лиспер, которого невозможность писать на любимом языке довела до тяжелой формы мизантропии.
Это наиболее приемлемый случай лапши. Я примерно так и делаю - и всё равно, с исключениями код выглядел бы проще, был бы короче, и менее error-prone - можно забыть проверку, и программа будет загадочно глючить, но необработанное исключение валит ее с хорошей диагностикой.
я в перле не шарю, однако глядя на перловый код в первую очередь бросается в глаза большое количество замысловатых символов, разнообразных скобок (хотя наезды на скопки свойственны обычно противникам лиспа) и использование индексов ([]?), явных числовых индексов (0..) и непонятных $i, $_, $#. Всего этого безобра прога на лиспе лишена. Кстати, как поместить в список в проге на перле один из элементов - тоже список? В лисповой проге тип значений в списке практически не влияет.
Этот код я произвёл задолго до начала изучения лиспа. С исключениями в с++ были связаны какие-то траблы, которые в том числе не позволяли юзать исключения в с++ коде в беосе. Подробности щяс не помню, завтре найду ссылку если хош.
> я в перле не шарю, однако глядя на перловый код в первую очередь бросается в глаза большое количество замысловатых символов, разнообразных скобок (хотя наезды на скопки свойственны обычно противникам лиспа)
Я не против скобок. Я против того, чтобы все скобки были одинаковые, как раз.
> и использование индексов ([]?), явных числовых индексов (0..) и непонятных $i, $_, $#.
Ну непонятны они только незнающим язык. Что такое mapcar и lambda нелисперу тоже трудно понять с первого взгляда.
> Всего этого безобра прога на лиспе лишена.
Вы считаете элементы списка не с нуля? И, кстати, запоминание индекса эффективнее, чем запоминание значения. И вообще, моя программа не требует наличия оператора эквивалентности для целевого типа.
Хотя можно и по значению, в общем-то, сложность только в том, что в перле нету универсального оператора эквивалентности. Для строчек - вот так:
sub permute(@) { @_ ? map { my $e = $_; map {[$e, @$_]} permute(grep {$_ ne $e} @_); } @_ : []; }
Ну, можно передавать лишний параметр - функцию эквивалентности.
> Кстати, как поместить в список в проге на перле один из элементов - тоже список? В лисповой проге тип значений в списке практически не влияет.
Данная перловая прога оперирует списками списков внутри (ну, на самом деле они массивы массивов - но это ортогонально теме совершенно, как mutable списки они тоже работают).
Короче, если ты ничего кроме лиспа толком не знаешь - молись на него дальше.
Ну блин все ядро так написано. А код с исключениями, имхо, не проще, а наоборот вовсе.
Вот каков будет скелет для "получить три ресурса, каждый из которых может бросить исключение, поработать, освободить все по порядку, вернуть результат-или-код-ошибки", с использованием явной обработки исключений?
Если нету классов, деструкторов и стековой дисциплины - то обработка исключений дает тот еще спагетти, я на Java этого насмотрелся.
нет, элементы списка не нумерованы. Это ведь не массив.
> И, кстати, запоминание индекса эффективнее, чем запоминание значения.
не факт, что индексы вообще нужны в большинстве случяев. Когда нужны - можно поюзать массивы, но они нужны по-нстоязему редко.
> Для строчек - вот так:
И всё-таки, приведи код на перле, осуществляющий перестановку наборов произвольных типов данных. В том числе и смешанных (когда внутре и строки, и символы, и целое, и с плавающей точкой, и другие наборы данных)
> Короче, если ты ничего кроме лиспа толком не знаешь - молись на него дальше.
Приятно было побеседовать. Только не расстраивайся так, что слил, может в другой раз не сольёш...
> И всё-таки, приведи код на перле, осуществляющий перестановку наборов произвольных типов данных. В том числе и смешанных (когда внутре и строки, и символы, и целое, и с плавающей точкой, и другие наборы данных)
Пилять, твоя функция тоже нихрена не работает, насколько я помню CL: она сломается, если у тебя будет в исходных данных два элементы, которые eq между собой (набор типа "1 1 1 2 2 2 3 3 3"), нет?
А моя исходная программа с индексами таки работает со списками чего угодно изначально. В том числи и смешанными.
Прошу прощения за опоздание :-)
Но вот тебе код на питоне, разумеется длиннее, чем на перле или
лиспе, но зато имхо лчуше читается, и возвращает не список, а
генератор и работает для списков гетерогенных :-) объектов
def permutations(e):
if not e:
yield []
else:
for p in permutations(e[1:]):
for i in xrange(len(e)):
new = list(p)
new.insert(i, e[0])
yield new
И что на лиспе решение лучше?
> Вот каков будет скелет для "получить три ресурса, каждый из которых может бросить исключение, поработать, освободить все по порядку, вернуть результат-или-код-ошибки", с использованием явной обработки исключений?
Ну, во-первых, RAII. Усли нет деструкторов:
try {
Resource r1 = new Res(), r2 = new Res2();
// используем ресурсы
} finally {
if (r1 != null)
r1.dispose();
if (r2 != null)
r2.dispose(); }
По-моему, это лучше, чем куча goto. И с нами остается главное преимущество исключений - необработанное исключение нельзя пропустить, а проверку кода ошибки - элементарно. К тому же не надо постоянно возвращать код ошибки - это тоже легко упустить.
> Если нету классов, деструкторов и стековой дисциплины - то обработка исключений дает тот еще спагетти, я на Java этого насмотрелся.
> Пилять, твоя функция тоже нихрена не работает, насколько я помню CL: она сломается, если у тебя будет в исходных данных два элементы, которые eq между собой (набор типа "1 1 1 2 2 2 3 3 3"), нет?
А ты проверь :P
> А моя исходная программа с индексами таки работает со списками чего угодно изначально. В том числи и смешанными.
как поменять изходник, приведённый тобой, чтобы проверить?
ИМХО намного. По тем же причинам, что и перловое. Использование индексов и циклов делает решение менее гибким и более низкоуровневым. Т.е. вместо понятия "скомбинировать каждый элемент списка с перестановками оставшихся" получяем "для каждого элемента из перестановок всех элементов, кроме первого ... (продолжи сам)". Не в том дело, что код получяется короче/длиннее (в разумных пределах), а то, что он понятийно более чужд и требует большего числа "подробностей".
В 2.4 - еще нет. Но, по мнению многих, это ни разу не трабл. Я склонен с ними согласиться - слишком необычным должен быть usage pattern, чтобы это вызывало реальные проблемы. По линку я не нашел внятного объяснения, какие проблемы вызывало такое поведение. "Неаккуратненько" - да, пожалуй.
> Использование индексов и циклов делает решение менее гибким и более низкоуровневым.
Дейкстра писал: "Ненавижу, бл#, людей, которые вместо цикла пишут рекурсию, потому что computer scinence говорит, что рекурсия круче" ;) Мораль в том, что в циклах нет ничего плохого или "низкоуровневого@&
> Дейкстра писал: "Ненавижу, бл#, людей, которые вместо цикла пишут рекурсию, потому что computer scinence говорит, что рекурсия круче" ;) Мораль в том, что в циклах нет ничего плохого или "низкоуровневого@&
Ну нету так нету. По моему мнению, нужна очень веская причина чтобы вводить переменную - счётчик цыкла (да, чясто такая причина есть, но приведённый пример, как мы видим на примере лисп-кода, не тот случяй) и понятие "i-тый элемент". Так можно договориться до того, что на асме битики перебирать ни разу не низкоуровнево.
Начнём с того что с моей точки зрения питон ведёт себя нормально. В 99.999999% случаев эта прооблема не возникает и никак не даёт о себе знать.
А во вторых этот парень наступил на грабли и стал на ломаном английском доказывать разработчикам питона что они мудаки. Его послали, а он в отместку написал статью что питон гавно, а разрвботчики казлы вкючая Тима Питерса, автора Zen of Python.
В то время как если ещё погуглить на эту тему, то найдётся страница какого-то иностранного программиста (не помню точно откуда), и вот он тоже наступил на эти грабли, но вместо того чтобы плакаться всему миру в жилетку он написал патч который эту фигню исправляет и собачился на списке рассылки, чтобы его патч приняли.
> Начнём с того что с моей точки зрения питон ведёт себя нормально. В 99.999999% случаев эта прооблема не возникает и никак не даёт о себе знать.
Станеш ли ты юзать <чтонибудь другое> если оно в xx% случаев ведёт себя нормально, а в оставшихся в произвольный момент времени может внезапно всбеситься и отрвать тебе яйтсы?
> Дык а я потом поинтересовался, чё _конкретно_ в ём нетак и как надо было?
Тот вопрос я прохлопал, сорри. Что не так - выглядит уродски и понять трудно. Как надо - там проскакивал фрагмент, я его назвал "наиболее приемлемым вариантом лапши". Его еще называют "отвал по отсосу", "goto по отсосу@ 8)
> а в оставшихся в произвольный момент времени может внезапно всбеситься и отрвать тебе яйтсы?
Во-первых, отнюдь не в произвольный момент - точно известно, что приводит к такой ситуации. Во-вторых, оно не бесится и не отрывает яйца - оно всего лишь занимает область виртуальной памяти в (оправданной, ИМХО) надежде, что она тебе понадобится. А не понадобится - уйдет в swap-файл. А на корректность функционирования это не влияет.
А ты не мог бы пояснить как именно у тебя комбинитурется первый
элемент списка с остальными элементами, а то я хоть убей не пойму как
работает версия на лиспе.
А на лиспе можно вернуть не список перестановок, а генератор?
А свое решение я сделал ещё до того как сказали здесь алгоритм, я
просто подумал что если это лисп то должна быть рекурсия, вот и
сделал тоже рекурсию :-)
def permutations(elems):
if not elems:
yield []
else:
for p in elems:
for lo in permutations(elems[:].remove(p)):
yield [p] + lo
Вот решение более похожее на твой алгоритм, но мне оно меньше
нравится, т.к. требуется чтобы над элементами списка была определена
операция сравнения, и чтобы не было элементов которые были бы "равны".
Соптимизировал своё оригинальное решение (с коллегами по работе :-)
выкинул две строки. Теперь получается вот что:
def permutations(e):
if not e:
yield []
else:
for p in permutations(e[1:]):
for i in xrange(len(e)):
yield p[:i] + [e[0]] + p[i:]
хм, почему? переписать на готы - так он вдвое длиннее будет как минимум. И готы в большом количестве и никак чтение проги не облегчают, это уж не только моё мнение.
> точно известно, что приводит к такой ситуации
главное, что точно неизвесно как избежать.
> оно всего лишь занимает область виртуальной памяти в (оправданной, ИМХО) надежде, что она тебе понадобится. А не понадобится - уйдет в swap-файл. А на корректность функционирования это не влияет.
не, ну хорошё прог на питоне пока большая редкость. А если запустить хотя бы пяток, и каждая станет виртуалку подгребать "на всякой случяй" и в своп её класть за ненадобностью... нунах! Да и сама суть траблы не позволяет с доверием относиться к.
>> Станеш ли ты юзать <чтонибудь другое> если оно в xx% случаев ведёт себя нормально, а в оставшихся в произвольный момент времени может внезапно всбеситься и отрвать тебе яйтсы?
Речь идёт не о "яйтсы", а о неосвобождении памяти.
В данном конкретном случае я не вижу никаких проблем. Меня это устраивает. Не перводи разговор в другую плоскость.
Кстати, чего это ты про память в питоне вспомнил? Это типа заместо "Да питон ацки крут, базара нет, лисп отсасывает, но зато у вас память не освобождается" :-)
Судя по твоей ремарке "может, хто и сблюванет", ты и сам разделяешь это субъективное мнение 8)
>> понять трудно
> хм, почему? переписать на готы - так он вдвое длиннее будет как минимум.
Не вдвое - у тебя там до фига строк, на которых только '||' или скобки. Код с goto будет плотнее.
> И готы в большом количестве и никак чтение проги не облегчают, это уж не только моё мнение.
"Не только мое" - это отсылка к "GOTO statements considered harmful"? Там речь шла о других goto - когда с их помощью переходят в тело цикла, или организуют цикл, или используют для организации подпрограмм в подпрограмме. В длинном флэйме, который последовал, было здравое предложение отделить мух от котлет - есть "плохие" goto, а есть "хорошие". И использование goto для того, чтобы имитировать обработку исключений в Си - это, ИМХО, "хорошие" goto. Во всяком случае, там обработка ошибок отделена от "нормального случая", что есть гуд.
если рассуждать "низкоуровневыми" терминами: mapcan применяет функцию поочерёдно к каждому элементу списка, а результат выполнения затем присовокупляет к списку-результату. Пример:
входной список - (1 10 100), функция - формирует список их двух элеметов, x*2 и x*3. Результат:
(2 3 20 30 200 300)
mapcar делает в сущности то же самое, только если функция возвращает список, он присовокупляется к результату как список, а не просто добавляются элементы результата. Пример
в проге перестановки mapcar перебирает элементы входного и скармливает их по одному первой lambda (e). Она в свою очередь вызывает функцию перестановки для входново списка с выкинутым элементом е (это (permutations (remove e x :count 1 :test 'eq))). Получает оттуда список, состоящий из списков-вариантов перестановок. Затем к каждому из этих списков присобачивает в начало выкинутый элемент е. Т.е. lambda (p) получает в качестве аргумента список p который является одним из вариантов перестановок исходного списка из которово выкинули элемент е. В результате, на выходе из mapcar - список из перестановок исходного списка, из которого выкинули е и затем добавили его к началу каждого. А на выходе из mapcan - все варианты данного действа, совершённого с каждым элементом входного списка поочерёдно.
> твой алгоритм
дело не в алгоритме, а в используемых понятиях. Один и тот же алгоритм можно записать на асме, и на сях и на чём угодно и работать он будет одинаково. Только на асме тебе придётся перестанавливать байтики, на сях - значения переменных, а на лиспе - применять функции к множеству. И, соответственно, на асме запись алгоритма для набора целых и для набора строк будет отличятся весьма и весьма, на сях - так, немного, а на лиспе - ровно настолько, насколько сама задача этого требует. Например если вместо 'eq записать '=, это будет работать только с целыми, а 'string= только с строками.
> а асме запись алгоритма для набора целых и для набора строк будет отличятся весьма и весьма, на сях - так, немного, а на лиспе - ровно настолько, насколько сама задача этого требует.
> Речь идёт не о "яйтсы", а о неосвобождении памяти.
Следует ли это понимать как "ну не ослободилась память, да и йух с ей"?
> В данном конкретном случае я не вижу никаких проблем.
Потому что непосредственно йайтсы не рискуют?
> Не перводи разговор в другую плоскость.
Почему? Я достаточно объёмен чтобы весть разговор в нескольких плоскостях единовременно. Ты нет?
> Кстати, чего это ты про память в питоне вспомнил? Это типа заместо "Да питон ацки крут, базара нет, лисп отсасывает, но зато у вас память не освобождается" :-)
Ну да, типо такого. С небольшими поправками. ИМХО траблы с оперативой - вещ достаточно суровая, чтобы юзать подверженное ей в продакшне. Когда за подобное действие проги разработчику вполне могут закащики йайтсы поотрвать. Это только не считая того, что я не вижу _принципиальной_ разницы меж питоном и тем же пхп например. А лиспом - вижу.
>> а асме запись алгоритма для набора целых и для набора строк будет отличятся весьма и весьма, на сях - так, немного, а на лиспе - ровно настолько, насколько сама задача этого требует.
> ИМХО траблы с оперативой - вещ достаточно суровая, чтобы юзать подверженное ей в продакшне.
@#$%, это НЕ трабл с оперативой. Просто программа будет занимать тот объем (виртуальной!) памяти, который ей _максимально_ нужен. И если ты запустил 5 задач, и сразу увидел, что у тебя не хватило памяти - это гораздо лучще, чем пускать 5 задач у себя и видеть, что всё ОК, а у заказчика эти 5 задач будут иногда отправлять систему в глубокий своп. Просто из-за того, что там фишка ляжет по-другому. А с текущим питоновским распределением памяти фишка _всегда_ ложиться одинаково и _предсказуемо_. Так что это не трабл ни разу.
> Судя по твоей ремарке "может, хто и сблюванет", ты и сам разделяешь это субъективное мнение 8)
Я просто признаю и соглашаюсь, что таковое мнение может иметь место. Раз уж я понаписал такое, значит и субъективно считаю приемлемым, и объективных проблем не вижу.
> Не вдвое - у тебя там до фига строк, на которых только '||' или скобки. Код с goto будет плотнее.
Какой смысел пустые/полупустые строки щитать? По символам ИМХО минимум вдвое длиньше будет.
> goto
А ты всё-таки попробуй переписать приведённый мной участок с готами, и сравним. Чё зря езыками трепацо? утя своё ИМХО умя своё, и пока кина не будет можно долго сопли жувать по этому поводу.