LINUX.ORG.RU

let сохраняет значения между вызовами функции

 


1

1

Решаю задания из «Gentle introduction to symbolic computation», там на 369 странице просят написать в итеративном стиле подсчет нуклеотидов в строке. Проще говоря, количество символов найти.

Набросал такой код:

(defun count-bases (strand)
  (let ((counts '((a . 0) (t . 0) (c . 0) (g . 0))))
    (dolist (e strand counts)
      (cond ((atom e) (incf (cdr (assoc e counts))))
            (t (incf (cdr (assoc (car e) counts)))
               (incf (cdr (assoc (cadr e) counts))))))))

Получилось в принципе похоже на код из ответов в конце книжки, только покороче:

(defun count-bases (dna)
  (let ((acnt 0) (tcnt 0) (gcnt 0) (ccnt 0))
    (labels ((count-one-base (base)
                             (cond ((equal base ’a) (incf acnt))
                                   ((equal base ’t) (incf tcnt))
                                   ((equal base ’g) (incf gcnt))
                                   ((equal base ’c) (incf ccnt)))))
      (dolist (element dna)
        (cond ((atom element) (count-one-base element))
              (t (count-one-base (first element))
                 (count-one-base (second element)))))
      (list (list ’a acnt)
            (list ’t tcnt)
            (list ’g gcnt)
            (list ’c ccnt)))))

Мой вариант работает как-то странно:

* (COUNT-BASES NIL)
((A . 0) (T . 0) (C . 0) (G . 0))
* (COUNT-BASES '(A G T A C T C T))
((A . 2) (T . 3) (C . 2) (G . 1))
* (COUNT-BASES '((A T) (T A) (C G) (G C)))
((A . 4) (T . 5) (C . 4) (G . 3))
* (COUNT-BASES (MAKE-DOUBLE '(A T G C)))
((A . 6) (T . 7) (C . 6) (G . 5))

Значения в cdr-частях переменной counts аккумулируются, хотя я ожидаю что они должны быть новые при каждом вызове let. Почему так происходит? Это особенность реализации (компиляю в sbcl)?


Особо не хочу вникать, но у тебя *тотально* неправильный код. Ты считаешь не только атомы, но и данные типа list. А твой код должен быть рекурсивным, вот прямо как пример в книжке. Если ты обнаружил атом, то ты инкрементируешь соответствующий элемент своего списка counts, а если не атом (то есть список), то рекурсивно вызываешь функцию (которая помечена labels). Рекурсия будет выполняться до тех пор, пока она не спустится на уровень атомов.

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

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

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

TLDR; Замени counts='(...) на counts=(list (cons A 0) ...).

У тебя проблема не в самом let, а в том, что ты запихиваешь в него единожды аллоцированный список '(...), который затем в несколько проходов меняешь.

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

Когда я игрался с самодельными лиспами, у меня объект '(...) попадал в рантайм прямо из ридера (в рантайме цикл проходит несколько раз по одному и тому же «коду», прочитанному ридером единожды). Полагаю, что в «больших» компилятора дело обстоит примерно также.

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

(list (cons A 0) ...).

Ну, только (cons 'a 0). Маленькая поправочка.

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

То есть он создаёт цепочку ((a . 0)...) и вытаскивает указатель на неё каждый раз когда видит такую же конструкцию?

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

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

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

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

Потому что в книжке '(не используется такая штука).

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

Пля, какой же бред. Какому идиоту пришло в голову __такое__ сделать? Лиспы...

Это ещё что :-) Лиспы хотя бы работают шустро, можно как-никак данные обсчитать относительно большого объёма за терпимое время выполнения :-) А вот какому идиоту пришло в голову делать тормозные интерпретатирешки, но зато ведь чтобы полностью ООП, чтобы аж даже буквы с цифрами были объектами :-) Лол :-)

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

А вот какому идиоту пришло в голову делать тормозные интерпретатирешки, но зато ведь чтобы полностью ООП, чтобы аж даже буквы с цифрами были объектами :-) Лол :-)

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

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

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

filequest
()

Наркоманы набежали. Всем спасибо, я вроде понял.

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

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

Из всех ли? :-) Как насчёт Smalltalk или Io? :-)

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

А там получается, за что боролись, на то и напоролись

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

The focus of programming language research for the last thirty years has been to combine the expressive power of high level languages like Smalltalk and the performance of low level languages like C. The results have neither been as fast as C or as expressive as Smalltalk. Io's purpose is to refocus attention on expressiveness by exploring higher level dynamic programming features with greater levels of runtime flexibility combined with simplified programming syntax and semantics.

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

Дада. Очередная окуенная история от всезнайки. Давай пример серьезного проекта на io. Или давай рассказывай как тот же майнкрафт тормозит.

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

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

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

Смоллток и Io тоже медленны, но по другим причинам. Они не платят за это мощностью

Ну так а кого это волнует в практике? :-) Если мне надо обсчитать несколько терабайт, и на лиспе можно накатать программу за 2 дня, которая обсчитает нужные данные за 6 часов, и можно будет двигаться дальше, забыв про причуды лиспа, то это лучше, чем если программу на цепепе буду писать неделю, потом 3 дня отлаживать, потом она за 1 час обсчитает :-) И это лучше, чем если за 2 дня накатать, потом она 2 дня считать будет на каком-нибудь тормозе :-) Ведь если что-то пойдёт не так, и программа на лиспе загнётся максимум почти через 6 часов, можно будет исправить и снова запустить :-) А вот когда она загнётся на тормозе почти через 2 дня и нужно будет запускать заново, то будет уже грустно :-) Мне нужен практический результат за кратчайшее время, а не скоростуха или идеальный инструмент :-)

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

однажды наблюдал такой случай. Чувак написал на жабаскрипте программу, которая содержала фильтр, и в соответствии с ним данные вывода менялись. У него были большие данные. Перформанс был полное говно, и он начал обсирать жабаскрипт, и его все поддерживали. Когда я вник в его проблему, выяснилось, что он использовал там кучу сахара, который чуть ли не на каждой итерации перерисовывал страницу (прямые манипуляции с DOM-объектами). Когда я переписал его говно, производительность увеличилась примерно в тысячу раз. Это показательный пример. В большинстве случаев, проблемы с производительностью обусловлены тупостью разработчика.

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

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

Не тупостью, а квалификацией :-) Это не одно и то же :-) Но ещё они обусловлены адекватностью инструмента :-) Давно уже известно, кажется, Ричард Гэбриел сказал, что написать тормозную программу на Лиспе очень легко, а на Си - практически невозможно :-) Факт в том, что и другой язык требуют квалификации :-) И факт в том, что на Лиспе можно писать довольно шустрые программы, но почти также же трудно, как и писать на Си программы, которые вообще работают, не падая :-) А вот на Смоллтоке или на Ио написать шуструю, соизмеримую по скорости с Лиспом программу, нельзя :-) Как и на Питоне :-)

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

А вот на Смоллтоке или на Ио написать шуструю, соизмеримую по скорости с Лиспом программу, нельзя :-) Как и на Питоне :-)

Я не любитель питона, но тут ты врёшь. Ибо есть библиотеки, реализованные на сях.

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

Я не любитель питона, но тут ты врёшь. Ибо есть библиотеки, реализованные на сях.

Нет, врут те, кто за счёт скорости библиотек на Си говорят о быстроте Питона :-) Питон тормоз :-)

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

Так можно очень далеко зайти. Или программы написанные с использованием таких библиотек не являются программами на питоне?

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

Так можно очень далеко зайти. Или программы написанные с использованием таких библиотек не являются программами на питоне?

Не надо никуда заходить :-) Возможность вызова сишных функций - это несомненно достоинство всякого языка, включая цепепе :-) Мне нужен практический результат за кратчайшее время, как уже было сказано :-) Т.е. лучше избегать всяких Си, т.е. лучше иметь дело с высокоуровневыми языками, которые приемлемо быстро работают :-) Если мне необходимо будет работать с Си, то я так и сделаю, без всяких питоно-лиспов-ио-смаллталк-рубей-джаваскриптов :-)

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

Чтобы использовать библиотеки, написанные на си, собственно на си писать совершенно необязательно.

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

вытаскивает указатель на неё каждый раз когда видит такую же конструкцию?

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

Вместо (list ... ) и т.п. можно просто копировать литерал (copy-tree '(...))

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 2)
Ответ на: комментарий от feofan

Чтобы использовать библиотеки, написанные на си, собственно на си писать совершенно необязательно.

Да я в курсе :-) Просто из того, что Питон может вызывать Си не следует, что Питон не тормоз :-)

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

Чтобы использовать библиотеки, написанные на си, собственно на си писать совершенно необязательно.

Да, и ещё :-) Чтобы использовать библиотеки, написанные на Си, нужно чтобы либо эти библиотеки уже существовали, и их нужно найти, либо написать их на всё том же Си :-) Ну и во-вторых, нужно создать биндинги к этим библиотеками на Си из того же Питона, если этого никто не сделал :-) Ну и в-третьих, при работе с большими объёмами данных, копирование данных из кучи Си в кучу какого-нибудь рантайма может быть неприемлемым из-за физических ограничений памяти :-) Поэтому, резонней взять средненький рантайм с приемлемой скоростью и без всяких Си (вообще) накатать быстро прототип :-)

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

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

FreeArc, XMonad — по сравнению с чем (с не меньшей функциональностью) тормозные?

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

xmonad — хороший пример. Когда то у меня стоял. Та функциональность, что он предоставляет — абсолютно минимальная функциональность. При этом, даже визуально было видно подтормаживание при переключениях. Я конечно все оконные менеджеры не пробовал, но думаю, с любым можно сравнивать, любой быстрей.

filequest
()

ОП, когда ты в CL пишешь кавычку (которая ') то в рантайме ВСЕГДА будешь получать один и тот же объект. Инициализация переменной в let - частный случай этого поведения.

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

Понял, неожиданно просто, первый раз столкнулся с этим.

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

язабан

Почему же? :-) Никогда вот не пробовал этих хацкель/лисп оконных менеджеров, но есть чувство, что всех их можно охарактеризовать одним словом на букву «г» :-) Все эти лиспы/хацкели хороши для экспериментов над данными, а не для написания оконных менеджеров для повседневной работы :-)

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