LINUX.ORG.RU

Racket VS Common Lisp

 , , , ,


8

10

Добрый день дорогие аналитики L0R'a. Ковыряю ракет, пишу на нем клиентскую программу - а пока хочется вот что спросить. Все же что лучше - Racket или Common Lisp? Что более перспективно? Ну и естественно, какие у одного недостатки/преимущества по сравнению с другим?

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

нет ни одного аналога жабских GC

А зачем аналог жабских гц? Есть другие языки и для них гц (не аналоги жабских) быстрее.

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

[default] lisp == common lisp

Нет.

и видеть как нативные спикеры

Не надо повторять за идиотами.

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

Тыщи библиотек.

и ни одной полноценной.

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

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

Есть.

2. Нормальной интроспекции типа (describe ...), (inspect ...).

Есть.

3. Оптимизации.

есть.

4. Сообщества.

Ну тут вообще все на столько лучше, чем в CL, что сравнивать и смысла нет.

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

2. Есть ли жизнь в связке vim + lisp? Или под лисп только емакс?

Есть плагин limp - жить можно, но лучше emacs

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

Проверку синтаксиса — можно, дебаггер — можно

Ни то, ни другое нельзя. То есть, в принципе, конечно, можно, но это будет десятое правило гринспуна. Для проверки синтатксиса нужны синтаксические объекты (вместо которых в общелиспе списки), дебагер велосипедится в общелиспе отдельным костылем (у racket прямая поддержка рантаймом через continuation-marks). По-этому в CL нихрена нормально и не сделано, в отличии от Dr.Racket.

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

Бредишь?

Нет.

В каком месте?

Да много где. Куда ни ткнись - ни хрена в нем нет.

Это что за взаимоисключающие параграфы?

Если люди назвались untyped нельзя уже на статике писать?

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

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

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

навскидку, биндинги к Qt, Gtk

Их нет, потому что есть встроенная гуйня (которая и так во многом биндинги к гтк), соответственно, никто и не парится.

anonymous
()

Все же что лучше - Racket или Common Lisp?

Ух ты, какая срачегенная тема! И да, общелисп лучше.

no-such-file ★★★★★
()
Ответ на: комментарий от anonymous

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

Пишу в SBCL:

(defun (test l)
  (when l
    (cons (/ 1 (car l)) (test (cdr l)))))

Запускаю (test '(1 2 3 0 5))

Вижу

Backtrace:
  0: (SB-KERNEL::INTEGER-/-INTEGER 1 0)
  1: (TEST (0 5))
  2: (TEST (3 0 5))
  3: (TEST (2 3 0 5))
  4: (TEST (1 2 3 0 5))
...

Сразу понятно на каком шаге и при каких данных произошла ошибка.

В Racket

(define (test l)
  (if (null? l) null
    (cons (/ 1 (car l)) (test (cdr l)))))

Запускаю (test '(1 2 3 0 5))

Получаю

/: division by zero

unsaved-editor1221: 5:10       (cons (/ 1 (car l)) (test (cdr l)))))

unsaved-editor1221: 4:2  skipped 3 duplicate frames
    (if (null? l) null
    (cons (/ 1 (car l)) (test (cdr l)))))

Значения переменных на момент падения не видны. Ладно, запускаю отладчик. Теперь на момент останова в стеке вижу

(/ ...)
(test ...)
(test ...)
(test ...)

Чтобы увидеть параметры приходится по ним щёлкать. Причём, параметры функции / увидеть нельзя вообще. Выполнить команду нельзя (REPL заблокирован). Можно только посмотреть стек и завершить программу.

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

нельзя сохранить продолжение из cl:mapcar

Подозреваю, что такого нет нигде, кроме схемы и еще может быть какой-то версии ML с родной поддержкой продолжений. В Haskell (Cont), F# (async workflow), Scala (continuation plug-in) такого точно нет, ибо типы не совпадают - там надо писать / использовать отдельную версию mapcar в точности как в CL.

Относительно продолжений я решил для себя так. Их нет в подавляющем большинстве языков, и ничего. Потому CL вполне может жить без них. Эдакий парадокс анти-Блаба :)

На счет генераторов последовательности. Они реализуемы и реализованы, как минимум, один раз через cl-cont. Это значит, что unwind-protect / handler-case / handler-bind / catch / throw использовать нельзя внутри таких генераторов, ну и бог с этим.

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

2. Нормальной интроспекции типа (describe ...), (inspect ...).

Есть.

Есть переменная с именем var. Какой командой мне узнать её тип, список полей, их значения. Если это функция, то список аргументов и их тип?

Даже в отладчике.

(struct c (head tail))

(define (test l)
  (if (null? l) null
    (c (/ 1 (c-head l)) (test (c-tail l)))))

Вижу нечитаемую строку типа:

l => #(struct:c 1 #(struct:c 2 #(struct:c 3 #(struct:c 0 #(struct:c 5 ())))))

Для двух полей ещё разобрать можно. А если бы это был GtkWidget с несколькими десятками и надо было узнать, например значение поля parent? Команду выполнить нельзя, только считать вручную глядя на описание структуры. В то время как в SBCL+SLIME инспектор позволяет просмотреть все поля и даже поменять их значения перед продолжением работы.

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

Подозреваю, что такого нет нигде, кроме схемы

Продолжения можно описать из самого языка на Smalltalk, Tcl и C, так как есть возможность работать со стеком или пространством имён.

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

Относительно продолжений я решил для себя так. Их нет в подавляющем большинстве языков, и ничего. Потому CL вполне может жить без них. Эдакий парадокс анти-Блаба

То же относится и к замыканиям. И к специальным переменным. И к макросам. Переходим на C++? Там есть всё остальное и он быстрее.

На счет генераторов последовательности. Они реализуемы и реализованы, как минимум, один раз через cl-cont.

Всё, что реализовано через cl-cont очень сильно тормозит.

(cl-cont:defun/cc list-cc (n) (loop for i from 1 to n collect i))

(defun list-n (n) (loop for i from 1 to n collect i))

(time (dotimes (k 10000) (list-cc k) nil))
Evaluation took:
  26.321 seconds of real time

(time (dotimes (k 10000) (list-n k) nil))
Evaluation took:
  1.052 seconds of real time
monk ★★★★★
()
Ответ на: комментарий от anonymous

3. Оптимизации.

есть.

Помоги тогда понять, почему на код

(require racket/unsafe/ops)
(define (test)
  (letrec ([oddp (lambda (x)
                   (if (zero? x) #f
                       (evenp (unsafe-fx- x 1))))]
            [evenp (lambda (x)
                    (if (zero? x) #t
                        (oddp (unsafe-fx- x 1))))])
    (oddp 400000000)))

Racket генерит кода на несколько килобайт (вот во что он его превращает: Typed Racket. Что я делаю не так? (комментарий)) и исполняет его 3 миллиона тактов, а SBCL на идентичный

(defun test ()
           (labels ((oddp1 (x) (declare (fixnum x))
                      (if (zerop x) nil
                          (evenp1 (1- x))))
                    (evenp1 (x) (declare (fixnum x))
                      (if (zerop x) t
                          (oddp1 (1- x)))))
             (oddp1 400000000)))

генерит

; disassembly for TEST
; 24235BB8:       840500000021     TEST AL, [#x21000000]      ; no-arg-parsing entry point
;       BE:       B800105E5F       MOV EAX, 1600000000
;       C3:       EB0E             JMP L1
;       C5: L0:   85C0             TEST EAX, EAX
;       C7:       741C             JEQ L4
;       C9:       83E804           SUB EAX, 4
;       CC:       85C0             TEST EAX, EAX
;       CE:       740B             JEQ L2
;       D0:       83E804           SUB EAX, 4
;       D3: L1:   840500000021     TEST AL, [#x21000000]
;       D9:       EBEA             JMP L0
;       DB: L2:   BA27001022       MOV EDX, 571473959
;       E0: L3:   8BE5             MOV ESP, EBP
;       E2:       F8               CLC
;       E3:       5D               POP EBP
;       E4:       C3               RET
;       E5: L4:   BA0B001022       MOV EDX, 571473931
;       EA:       EBF4             JMP L3

который выполняется 600 тысяч тактов (в 5 раз быстрее).

И как заставить Racket нормально соптимизировать код?

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

Сообщества.

Ну тут вообще все на столько лучше, чем в CL, что сравнивать и смысла нет.

Можно аналог common-lisp.net, lisper.ru и planet.lisp.org для Racket?

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

Продолжения можно описать из самого языка на Smalltalk, Tcl и C, так как есть возможность работать со стеком или пространством имён.

О, да, про Smalltalk и posix я как-то подзабыл :)

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

То же относится и к замыканиям. И к специальным переменным. И к макросам. Переходим на C++? Там есть всё остальное и он быстрее.

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

Всё, что реализовано через cl-cont очень сильно тормозит.

Знаю. А что делать?! Шашечки или ехать.

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

Всё, что реализовано через cl-cont очень сильно тормозит.

Причем, можно было бы заметно ускорить, если бы семантика лиспа позволяла определять что-нужно преобразовывать, а что нет. Cl-cont пережевывает все подряд, что надо и что не надо. Достаточно взглянуть на macroexpand.

А вот, тот же F# очень избирательно подходит к тому, что преобразовывать. Причем, циклы F# преобразует достаточно эффективно на мой взгляд. В моих простых тестах F# async workflow, основанный на трех (sic !) продолжениях, был быстрее cl-cont в несколько раз, который оперирует только одним продолжением.

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

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

Вообще-то позволяет. Никто не мешает внутри cl-cont описать преобразование loop, iterate, dotimes, dolist. Просто это усложнит cl-cont.

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

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

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

Был бы ещё racket удобнее... Для emacs есть geiser, похожий на SLIME, но проблемы с отсутствием дебаггера и инспектора те же.

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

Вообще-то позволяет. Никто не мешает внутри cl-cont описать преобразование loop, iterate, dotimes, dolist. Просто это усложнит cl-cont.

Боюсь представить такое чудище.

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

Я здесь имел в виду то, что вычисления (или продолжения, или что другое) в F# возможны только в четко обозначенных местами при помощи ключевых слов let!, do! или use!. Все остальное не подвергается преобразованию. Проблема с call/cc в лиспе в том, что эта форма теоретически может появиться в любом месте. Поэтому было бы эффективнее это дело как-то ограничить.

Исходники F# довольно легко читаются. Например, так код в разы красивее, чем в реализации библиотек Scala.

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

В cl-cont не в любом. Только внутри with-call/cc.

А в F# можно отдельно скомпилировать аналог mapcar, а потом изнутри переданной в него функции сохранить продолжение?

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

торрент-клиент можно написать на PyQt за день с перерывами на сон и спортзал

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

Etch
()

Немного оффтопик (про родственный язык), но не хочу создавать новую тему. Извенити, если что-то вдруг не так. Вот, короче, прочитал умные книжки: Армстронга в оригинале и переводную Франческо Чеззарини. Разобрался, как устроены такие софтинки как ejabberd и rabbitmq. Освоил основные паттерны разработки, использующиеся в эрланге. Написал собственную реализацию вебсокетов, ибо все обнаруженные мной не понравились. Насколько целесообразно дальнейшее написание программ на этом языке программирования? Насколько востребованы программисты в Москве? Я сам родом из Ульяновска, приехал после института покорять столицу, а также искать москвичку, чтобы жениться, вселиться в её квартиру и таким образом получить московскую прописку. Умею ещё скриптовать бухгалтерию на 1С, начинал изучать Java, но не осилил, потому что мозг уже, конечно не тот, да и седина на мудях сказывается. Вот такие пирожки с KАТЯтами.

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

В cl-cont не в любом. Только внутри with-call/cc.

В F# ограничения для let!, do! и use! еще жестче. Там может быть много кода, который преобразовывать не надо. Так и происходит выигрыш в производительности.

А в F# можно отдельно скомпилировать аналог mapcar, а потом изнутри переданной в него функции сохранить продолжение?

Да, почему же нет? Функция должна возвращать Async<'a>. Внутри своего mapcar ее нужно включить в вычисление Async через let!. Возвращаясь к переданной функции, нужно будет составить вычисление Async<'a> возможно через Async.FromContinuations, куда и подсунуть свои продолжения-перехватчики.

Такой же финт ушами можно сделать и в Haskell, и в Scala, если я правильно понял твою задачу.

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

Внутри своего mapcar ее нужно включить в вычисление Async через let!

Я имел в виду, что mapcar ожидает обычную функцию, а получает, возвращающую продолжение. Похоже нельзя.

Идею F# понял. В cl-cont предполагается. что нужные куски пользователь сам обернёт в with-call/cc и without-call/cc.

Для своего кода это работает, а вот как только пытаешься использовать любой внешний, начиная от mapcar, dolist, заканчивая каким-нибудь map-sql-rows, так сразу возникает проблема, что чужую библиотеку надо переписыватть. Или из вызова map-... вернуться нельзя.

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

Умею ещё скриптовать бухгалтерию на 1С

За 1С платят больше. Особенно в Москве.

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

Ну, так. Либо схема с ее формой call/cc, запоминающей стек, либо явное преобразование кода, пусть и через сахар вычислительных выражений, нотаций do, плагинов и коудвокеров. Чудес не бывает. Хотя в качестве мозгового штурма: а что если через FLI из лиспа вызвать сишный код, а там вставить setjmp/longjmp? Выглядит бредово, но чем черт ни шутит?

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

На кой тебе эта убогая маськва?

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

там вставить setjmp/longjmp

Пробовали. Проблема в виртуальной машине и сохранении тех аргументов, что в регистрах.

http://formlis.wordpress.com/2010/08/20/hack-co-routines-in-sbcl-lisp/

http://random-state.net/ — вот здесь, надеюсь, товарищ допилит фиберы на SBCL, тогда можно будет запилить продолжения на них (потому как на потоках OS или cl-cont всё очень медленно).

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

Так уж ни один? В ракете нет гигиенических макросов? Стандартизованной оптимизации хвостовых вызовов? Продолжений? Или (с другой стороны) есть стандартные сигналы-рестарты как в CL?

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

В СПб есть центры разработки как минимум трёх компаний, где используется erlang. Одна из них называется «Яндекс».

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

Racket генерит кода на несколько килобайт (вот во что он его превращает: Typed Racket. Что я делаю не так? (комментарий)) и исполняет его 3 миллиона тактов

Потому что должен, для сохранения семантики.

который выполняется 600 тысяч тактов (в 5 раз быстрее).

Потому что общелисперам похуй на сохранение семантики и совместимость кода.

И как заставить Racket нормально соптимизировать код?

Никак. Заставить генерить код как в sbcl = заставить генерить некорректный код с undefined behavior и рандомными непредсказуемыми багами.

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

Запускаю (test '(1 2 3 0 5))
Вижу

Ну это ложь. Чтобы запустить код и увидеть трейс - надо запускать код с работающим трейсером. Точно так же как и в Racket.

А на (debug 0) (safety 0) вообще будет simple-error на любую ошибку без указания ее места даже примерно. Если вообще укажет ошибку.

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

Как нельзя? А почему все видят? Может, если все видят, а ты - нет, проблема в тебе? Алсо, тебе надпись «skipped 3 duplicate frames» ничего не намекнула?

Выполнить команду нельзя (REPL заблокирован).

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

Вообще я хз. Возможности дебага в Racket НАМНОГО шире, чем в SBCL (как раз дебаг я считаю одним из главных преимуществ Racket над SBCL).

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

Есть переменная с именем var. Какой командой мне узнать её тип, список полей, их значения. Если это функция, то список аргументов и их тип?

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

Вижу нечитаемую строку типа:

А что ты там хотел видеть? Кучу непонятного неразборчивого поноса?

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

Можно аналог common-lisp.net, lisper.ru и planet.lisp.org для Racket?

маиллист ракеты с запасом перекрывает все три перечилсенных ресурса в совокупности.

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

Был бы ещё racket удобнее... Для emacs есть geiser, похожий на SLIME, но проблемы с отсутствием дебаггера и инспектора те же.

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

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

Так уж ни один?

Ни один.

В ракете нет гигиенических макросов?

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

Стандартизованной оптимизации хвостовых вызовов?

Или (с другой стороны) есть стандартные сигналы-рестарты как в CL?

Конечно. Рестарты на продолжениях реализуются в пару-тройку десятков строк.

Стандартизованной оптимизации хвостовых вызовов? Продолжений?

А чем это плохо?

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

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

Какой функцией узнать тип переменной? Если переменная — класс, то как получить список имён полей?

А что ты там хотел видеть?

Нормальную структуру типа http://2.bp.blogspot.com/_XshvghKxGuU/SgxkCwOMdeI/AAAAAAAAAAk/40qtu8p4J-c/s16...

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

чтобы хотя бы найти место возникновения ошибки надо с бубном оттанцевать

Не понял. Я же тебе показал в SBCL/SLIME. И место ошибки показывает и какие значения в этот момент передавались. А в Racket значения только при запуске в отладчике увидеть можно, и то в виде строки.

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

И место ошибки показывает

Это где он показывает? Ни файла, ни строки, ни позиции в строке нету там.

А в Racket значения только при запуске в отладчике увидеть можно, и то в виде строки.

Так тот трейс что ты показал - это и есть запуска в отладчике. Я не понимаю, почему ты запуск общелиспа в отладчике сравниваешь с запуском Racket без? Давай либо и там и там отладчика нет, либо и там и там отладчик есть.

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

Ну это ложь. Чтобы запустить код и увидеть трейс - надо запускать код с работающим трейсером.

Так включен. В «выбрать язык» стоит «Отладить».

А почему все видят? Может, если все видят, а ты - нет, проблема в тебе? Алсо, тебе надпись «skipped 3 duplicate frames» ничего не намекнула?

Покажи скриншот трейса, где видно, чему равен l в момент падения. skipped 3 duplicate frames: ну указал он, что функция выполнялась трижды. Не всегда функция является проходом по списку, обычно нужны значения на последних нескольких итерациях перед падением, чтобы понять из-за чего упало.

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

И? Разница-то в чем?

На CL можно прикрутить типизацию, но typed racket есть, а typed cl «может быть реализован». Тоже разницы нет?

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

Какой функцией узнать тип переменной?

Проверить каждый.

Если переменная — класс, то как получить список имён полей?

class-info?

Нормальную структуру типа http://2.bp.blogspot.com/_XshvghKxGuU/SgxkCwOMdeI/AAAAAAAAAAk/40qtu8p4J-c/s16...

Не понял, а с чего тебе ее должно выдать? В общелиспе ведь не выдает.

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