LINUX.ORG.RU

Racket VS Common Lisp

 , , , ,


8

10

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

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

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

Ровно это и сказано в списке. Значит, уже не ни один.

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

Это ничем не плохо, но это есть в том списке. Значит, уже как минимум три.

Но да, сравнение там ровно того, что сказано. Т.е. не racket и CL, а Scheme и CL.

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

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

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

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

Скриншот с общелиспа вообще-то.

Ложь:

* 1

1
*
и никакого описания типа «целое число» мне не выдало.

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

class-info?

> (define frame (new frame% [label "Example"]))
> (class-info frame)
. . class-info: contract violation
  expected: class?
  given: (object:frame% ...)
> (class-info frame%)
. . class-info: current inspector cannot inspect class
  class: #<class:frame%>

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

Суровые схемеры...

Кстати для класса в отладке вообще ничего не выдает. В отладке пишет «f => #(struct:object:frame% ...)». А как его поля увидеть?

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

Это ты что запустил? Надо запускать Emacs и в нём команду slime: http://common-lisp.net/project/slime/doc/html/index.html

А то я тоже запущу вместо drracket просто racket и буду рассказывать, что там IDE нету.

и никакого описания типа «целое число» мне не выдало.

Так надо

> (type-of 1)
BIT

А в схеме такой функции нет. Разве что typed racket запускать.

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

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

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

Похоже просто разные подходы к обеспечению живучести. В racket, скажем, нельзя переопределить функцию загруженного модуля без перезапуска, в то время как в лиспе это основной метод разработки: занёс тестовые данные в переменные, запусти функцию, не понравилось, тут же исправил функцию, снова запустил.

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

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

В MIT Scheme рестарты почти идентичны лисповым

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

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

-> (define (f n) (if (= n 0) n (/ n (f (sub1 n)))))
-> (trace f)
-> (f 5)
>(f 5)
> (f 4)
> >(f 3)
> > (f 2)
> > >(f 1)
> > > (f 0)
< < < 0
; /: division by zero [,bt for context]
->
anonymous
()
Ответ на: комментарий от monk

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

Что характеризует нужность трейсеров и неадекватного общелиспового дебагера.

В racket, скажем, нельзя переопределить функцию загруженного модуля без перезапуска

Можно (гейзер-то как-то работает?), надо только выставить (enforce-module-constants #f).

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

class-info?

Надо сперва object-info (вернет класс объекта), а потом уже class-info. Но работает это, естественно, только в том случае, если у тебя есть доступ к соответствующим структурам/классам. То есть только для определенных тобой структур.

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

А в схеме такой функции нет.

Ну она легко пишется. (cond [(char? x) 'char] [(integer? x) 'integer] ...). Примитивных типов мало.

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

И опять ничего не видно:

-> (trace frame)
-> (define frame (new frame% [label "Example"]))
-> (test frame)
>(test (object:frame% ...))

Строчка (object:frame% ...) не разворачивается.

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

И опять ничего не видно:

Не понял, а что ты должен видеть?

Строчка (object:frame% ...) не разворачивается.

Она и не должна. Это же тебе не #:opaque структура, доступ к ее полям из вызывающего кода в данном случае закрыт.

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

И trace надо с большой осторожностью применять, если в параметрах длинные списки.

(define (test n)
    (count (for/list ([i (in-range n)]) i)))

(define (count l)
  (foldl + 0 l))

(trace test)
(trace count)

(test 100)

он выдал все 100 элементов в колонку. А если бы там был не foldl, а рекурсивный вызов...

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

Это же тебе не #:opaque структура

вы имели в виду не #:transparent?

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

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

Вот я и говорю, что нормальной интроспекции в racket нет. Либо на каждый тип писать свой (describe-something ...) и весь код заворачивать в with-handlers. Либо в момент падения увидишь только кучу многоточий и хорошо, если падение вопроизводимо, а если это ошибка пользовательского интерфейса...

И сразу связанный вопрос: аналоги cl-store для racket существуют? В смысле, сериализация произвольного объекта в текст и обратно.

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

Можешь настроить себе любой вариант.

Уже пробовал. От объектов всё равно только имена классов и многоточия.

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

Вот я и говорю, что нормальной интроспекции в racket нет.

Ты не понял. Она есть, но он _закрыт намеренно_. Для этого (чтобы ты туда кривыми руками не лазил) там целая система с инспекторами предусмотрена.

И сразу связанный вопрос: аналоги cl-store для racket существуют? В смысле, сериализация произвольного объекта в текст и обратно.

Ну если там вот так:

CL-STORE currently supports serialization of

All numbers (float, ratios, integers, complexes)
Character, and Strings
Vectors and Arrays
Hash Tables
Lists
Instances of Structures
Instances of CLOS Classes
Conditions
CLOS Classes
Structure definitions (SBCL and CMUCL only)
Functions (Serializes the function name)
Generic Functions (Serializes the GF Name)
And Combinations of the above
то да: http://docs.racket-lang.org/reference/serialization.html?q=serialize#(def._((...

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

Уже пробовал. От объектов всё равно только имена классов и многоточия.

А дебаг тут не при чем, если ты умудришься-таки залезть внутрь объектов - надо будет писать багрепорт.

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

то да: http://docs.racket-lang.org/reference/serialization.html?q=serialize#(def._((...

Не работает.

> (define frame (new frame% [label "Example"]))
> (serialize frame)
. . serialize: contract violation
  expected: serializable?
  given: (object:frame% ...)

А в cl-store «Instances of CLOS Classes» нормально сериализуются.

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

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

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

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

То есть такое поведение не баг, а фича...

Интересно, а как тогда отладку проводить? Лазить в чужие модули и дописывать аксессоры? Потому как у 90% объектов racket функции «получить текущее состояние» просто нет.

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

Интересно, а как тогда отладку проводить?

Никак. Эти модули уже написаны и отлажены. И именно за тем чтобы ты туда не лез и не ломал ничего своей «отладкой» доступ и закрыт.

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

А в cl-store «Instances of CLOS Classes» нормально сериализуются.

Датычо? Ну положи в слот несерализуемый объект и сериализуй.

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

define-serializable-class

То есть объекты библиотечных классов в пролёте. Круто. Если я свой класс пишу, то мне и (send my-object serialize) не влом сделать будет. А вот если у меня, скажем, дерево или очередь, то я уже в пролёте.

Ну ладно, объекты в racket не в почёте (на них только gui), но структуры тоже сериализовать можно только prefab или serializable, а в библиотеках они определены через struct или struct: (если typed racket) без prefab.

А значит, если пишешь, например, ORM, то в обязательном порядке форкаешь библиотеки для всех типов данных, которые собрался сохранять. Так что-ли?

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

несерализуемый объект

Сделать несериализуемый объект в CL — это надо постараться. В перчисленный в cl-store список не попадают разве что открытые файлы, случайные состояния, адреса в FFI и такая же редкость.

Произвольный класс, взятый из произвольной библиотеки сериализуется с вероятностью в 90%. Более того, если мне очень надо сделать сериализуемым то, чего нет в списке, я просто доопределю defmethod на соответсвующий тип. А в Racket ровно наоборот: если я специально сделаю объект сериализуемым, тогда он сериализуется, а если я хочу сериализовать, например, очередь, то мне надо сделать форк библиотеки, где она описана. Разве не бред?

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

и отлажены... не ломал ничего своей «отладкой» доступ и закрыт

Круто! В Racket знаяют секрет написания абсолютно безошибочного кода?

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

Произвольный класс, взятый из произвольной библиотеки сериализуется с вероятностью в 90%.

На самом деле около нуля, т.к. ф-и не сериалзуются, но в общелиспе эта проблема вместо решения просто заметается под ковер. И в результате то что твой объект некорреткно сериализован ты можешь узнать спустя год, ВНЕЗАПНО совершенно.

Разве не бред?

Конечно, не бред. Все так и должно быть - сериализуемые объекты - сериализуются, несериализуемые - не сериализуются. В общелиспе же сериализуется все, но некорректно, то есть функция serialize/deserialize тебе доложит об успехе, но пользоваться объектом ты не сможешь. И в чем же профит?

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

Круто! В Racket знаяют секрет написания абсолютно безошибочного кода?

Я не понимаю, ты собрался отлаживать ракетовские библиотеки с гуйней?

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

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

Ну сделай serializable враппер вокруг этих структуры-класса, кто тебе мешает?

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

ф-и не сериалзуются

Функции сериализуются по имени. А тело функции у тебя всё равно в программе. Безымянные не сериализуются и узнаешь ты об этом сразу при попытке сериализации.

И в результате то что твой объект некорреткно сериализован ты можешь узнать спустя год, ВНЕЗАПНО совершенно.

Неправда. Если тип не сериализуется, то узнаешь ты об этом сразу.

Все так и должно быть - сериализуемые объекты - сериализуются, несериализуемые - не сериализуются.

При этом все библиотечные типы данных являются несериализуемыми. И дописать к ним сериализацию постфактум тоже нельзя (потому как модуль закрыт). Только форкать. И будет отдельно, например, datastruct, и отдельно datastructs/serialize, ..., pfds и pfds/serialize и так далее.

И периодически придётся делать copy/paste из основных веток, чтобы версии не сильно различались. Печальная картина.

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

собрался отлаживать ракетовские библиотеки с гуйней

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

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

Ну сделай serializable враппер вокруг этих структуры-класса

Это как?

> (define-serializable-class test% frame% 
    (super-new))
. . class*: superclass is not serialiazable, not transparent, and does not implement externalizable<%>
  superclass: #<class:frame%>
  class name: test%
monk ★★★★★
()
Ответ на: комментарий от monk

Я собрался отлаживать код, их использующий.

Замечательно - отлаживай. Тебе никто не мешает.

желательно знать какие поля интерфейса какие значения в этот момент имеют.

Ради бога. Ко всем нужным тебе полям доступ есть.

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

Функции сериализуются по имени.

То есть не сериализуются.

Неправда. Если тип не сериализуется, то узнаешь ты об этом сразу.

Ну так классы не сериализуются выходит. Чего ты тогда мозг паришь?

При этом все библиотечные типы данных являются несериализуемыми.

Ну так ф-и не сериализуются.

И дописать к ним сериализацию постфактум тоже нельзя (потому как модуль закрыт).

Да почему не можешь-то?

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

Ко всем нужным тебе полям доступ есть.

Доступ есть. Например, я могу сделать (send frame get-label) и получить содержимое поля. Но я не могу сделать этого в отладчике. И поля label я в отладчике увидеть не могу. Получается, единственный вариант — писать свой «отладчик», который вешать на with-handlers на все функции.

Вот про это я и говорю, что по сравнению с SBCL+SLIME, в DrRacket отладчика нормального нет (тот что есть не позволяет ничего сделать), интроспекции нет (у полученного объекта средствами отладчика ничего нельзя увидеть). Хотя не спорю, задача потенциально решаемая.

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

Функции сериализуются по имени.

То есть не сериализуются.

А что ещё у функции кроме имени есть? Всё остальное в коде. А если код меняется, так при изменении формы (define-serializable-... ) тоже десериализация сломается.

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

И какая прелестная ошибка выскакивает (сериализовал класс, затем добавил ему поле):

> (deserialize ss)
. . car: contract violation
  expected: pair?
  given: '()

Кто-там говорил про «очевидность места ошибки»?

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

И поля label я в отладчике увидеть не могу.

Потому что тебе и не надо, все верно.

Получается, единственный вариант — писать свой «отладчик», который вешать на with-handlers на все функции.

При чем тут отладчик, еще раз? Отладчик - отдельно, видимость структур - отдельно.

Ну и, кстати, благодаря continuation-marks написание отладчика - очень тривиальная задача.

Вот про это я и говорю, что по сравнению с SBCL+SLIME, в DrRacket отладчика нормального нет (тот что есть не позволяет ничего сделать), интроспекции нет (у полученного объекта средствами отладчика ничего нельзя увидеть). Хотя не спорю, задача потенциально решаемая.

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

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

Как сделать, например frame% сериализуемым.

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

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