Проклятый Common Lisp

Ещё в июле я, добравшись до описания ввода-вывода в SWI-Prolog, понял, что вид этого параграфа будет сильно зависеть от того, что получится в параграфах, посвящённых вводу-выводу в Common Lisp и Scheme; самих этих параграфов на тот момент не существовало, я оставил их "на потом" вместе с тонкостями эксплуатации интерпретаторов.

Сказать, что создание соответствующего параграфа пошло через гадину — это ничего не сказать. Сегодня я ввод-вывод Common Lisp, наконец, добил, заодно убедившись, что "стандарт" Common Lisp, как и положено стандартам, ни на что не годится, но, в отличие от других языков, для Common Lisp создатели конкретных реализаций пошли дальше стандартизаторов и сотворили нечто ещё хуже, чем исходный стандарт. Рассматривал я SBCL, ECL и GCL; чтобы объяснить, как написать простую программу, которая всего-навсего не вываливается в отладчик при возникновении ошибки открытия файла и при нажатии Ctrl-C (и я ни фига не шучу), пришлось написать 15 страниц текста, причём до какой-то приемлемой степени это удалось только с SBCL (сообщение permission denied напечатать можно, но оно выглядит так, как хочет интерпретатор, а не программист); в ECL в объекте исключения информация о конкретной ошибке отсутствует (нет, не шучу, я серьёзен!), в GCL исключения вообще невозможно перехватить — интерпретатор вроде бы знает о существовании соответствующих примитивов, но при попытке их применить говорит, что такие функции у него не определены. Других свободно распространяемых (и при этом живых) реализаций Common Lisp я не нашёл. Похоже, Лисп всё-таки намного мертвее, чем мне бы этого хотелось.

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

UPD:Между делом, по объёму четвёртый том сравнялся с самым толстым из первых трёх (496 страниц), при этом писать там ещё довольно много. Мне уже интересно, удастся ли это всё загнать хотя бы в 600.

Это пример для

Это пример для иллюстрации обработки исключений в CL?

Если нет, то не лучше ли было сделать наоборот: сначала проверить, что файл доступен, а уж потом с ним работать? Всё-таки недоступный файл — ситуация не исключительная, а вполне штатная.

Питонисты, кстати, очень продвигают такой подход: сначала делаем без каких-либо проверок, а потом ловим ошибки. Любят по этому поводу приводить цитату от Грейс Хоппер (которая, всё-таки, несколько по другим, более армейским, поводам была сказана).

А какой подход к обработке ошибок считаете разумным вы?

Какой ЯП, такие и "программисты"

Питонисты, кстати, очень продвигают такой подход: сначала делаем без каких-либо проверок, а потом ловим ошибки.

Учитывая уровень порога входа в этот ЯП, это неудивительно. Поделия на питоне - это вообще сборник крайне кривых и глючных "решений". Питономакак вообще не смущает тот факт, что они создают "софт" на скриптовом языке, причём очень посредственном. Он даже в роли скриптового языка практически неприменим, потому что представляет собой кривое поделие.
Поэтому все "практики" кодерков на питоне - это одно сплошное недоразумение, т.к.:
1) Питон - это ущербный ЯП, который нормальный специалист даже не считает за таковой.
2) Питон используют люди, которые вообще мало что понимают в разработке ПО, судя по генерируемым ими "решениям". Не делать проверок, а вместо этого ловить ошибки - это просто лютый манкикодинг.

Это пример для

Это пример для иллюстрации обработки исключений в CL?

Разумеется, нет. Изначально я вообще не планировал рассматривать обработку исключений в Лиспе, особенно в CL, где она намертво завязана на CLOS — который, в свою очередь, выглядит примерно столь же нелепо, как рога у рыбы.

начала проверить, что файл доступен, а уж потом с ним работать?

Во-первых, этого сделать нельзя, ни в спецификации CL, ни в рассмотренных мной интерпретаторах нет соответствующих средств. Точнее, режим открытия probe есть, но он не решает никаких проблем: если ошибка состоит не в том, что файла не существует, а в чём-то другом — хоть тот же permission denied — то интерпретаторы впадают в истерику (длинная простыня диагностики, запуск отладчика, вот это вот всё).

Во-вторых, вы знаете такой термин race condition? Если что: в любой серьёзной конторе за это вот "сначала проверить, потом работать" вас, может, и не уволят (ибо даже программист-идиот нынче всё-таки лучше, чем незакрытая вакансия), но к важным фрагментам кода больше не допустят. Не могу удержаться от комментария, что авторы Common Lisp этого не знали (иначе им бы в голову не пришло этот вот probe придумать), что лишний раз характеризует техническую стандартизацию как явление.

Всё-таки недоступный файл — ситуация не исключительная, а вполне штатная.

Я вам больше скажу: абсолютно любая ошибка при открытии файла — это штатная ситуация. А теперь объясните это тем безмозглым тварям, которые придумали Common Lisp, и тем, которые написали SBCL, ECL и GCL.

Питонисты, кстати,

Я бы предпочёл другой подход: всем, у кого есть опыт работы на Питоне, запретить программировать вообще.

А какой подход к обработке ошибок считаете разумным вы?

Очень простой: если произошла ошибка, то библиотечная функция, в которой она произошла, обязана об этом сообщить головной программе. Всё, точка. Никаких самостоятельных действий, никакой истерии, никаких дебаггеров и т.п., всё это привилегии головной программы. А что, существует какое-то иное мнение на этот счёт?

И вот что, по-моему вы сюда зря припёрлись.

Тот мой

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

И вот что, по-моему вы сюда зря припёрлись.

Вы, Андрей, ко мне несправедливы. Я всего лишь не очень опытный программист, у которого есть по некоторым вопросам каша в голове и который при этом очень ценит ваш труд (я про книги) и ваше мнение. За каковым мнением я сюда и "припёрся". А вовсе не поспорить или потроллить, как вам, вероятно, показалось.

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

вы знаете такой термин race condition?

Знаю. Действительно, не подумал о том, что

if (file accessible) then (open file)

подвержен race condition, в отличие от

try (open file) catch (errors)

Заставили задуматься, спасибо.

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

Очевидно, в Common Lisp так и происходит: библиотечная функция сообщает об ошибке головной программе. В случае Common Lisp головной программой является интерпретатор. А далее уже интерпретатор пользуется своими привилегиями и запускает дебаггер. (У SBCL есть опция --disable-debugger и функция (disable-debugger).)

Но в целом суть проблемы понятна: Common Lisp плохо приспособлен к взаимодействию с вышестоящей операционной системой.

Вы, Андрей, ко

Вы, Андрей, ко мне несправедливы.

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

if (file accessible) then (open file)

Между прочим, я, пожалуй, погорячился, употребляя термин race condition. То есть он, конечно, верный в этой ситуации, но объяснить всё можно ещё проще: в системе, кроме вашей программы, есть кто-то ещё, и этот кто-то (точнее, эти кто-то, ибо их много) могут в любой момент файл стереть, переименовать, изменить права доступа и т.п.; следовательно, проверка "доступности" файла никак не гарантирует, что он останется доступен спустя те несколько микросекунд, когда наша программа таки дойдёт до open.

try (open file) catch (errors)

А этот подход лучше всего описывается характеристикой «из пушки по воробьям». Собственно говоря, создатели Common Lisp, похоже, и не предполагали, что он будет применяться в этой ситуации — они настолько не желали ни о чём думать, что всерьёз решили, будто ошибки при открытии файла можно не обрабатывать.

в Common Lisp так и происходит: библиотечная функция сообщает об ошибке головной программе. В случае Common Lisp головной программой является интерпретатор

Головная программа — это та программа, которую написал программист. Интерпретатор себя таковой считать не имеет права, а если всё-таки считает — то он ни на что не годится, и это в полной мере относится ко всем трём интерпретаторам CL, которые я успел пощупать.

У SBCL есть опция --disable-debugger и функция (disable-debugger)

эта опция даже включена по умолчанию, если SBCL использовать как интерпретатор скрипта (с опцией --script). Это никак не спасает от простыни диагностики на полтора экрана (трассы вызовов функций) и итогового падения программы при возникновении ошибки при открытии файла. Ну и, опять же, простыня диагностики при нажатии Ctrl-C — это тоже ни в какие ворота не лезет.

Common Lisp плохо приспособлен к взаимодействию с вышестоящей операционной системой.

Я бы сказал, что он вообще никак не приспособлен для написания отчуждаемых программ, то есть таких, которые можно передать пользователю. Что до взаимодействия с ОС, то оно там, конечно, через задницу, но главное не это — главное то, как SBCL (и вся остальная компания) «взаимодействует» с выполняющейся в них программой.

общинные лиспы

GCL

Как вы его найти-то умудрились? :)

Нигде, ни в одной книге по CL, ни на одном сайте или блоге, посвящённом изучению CL, ни в одном живом обсуждении CL я упоминания (не говоря уже про рекомендацию к использованию) этого GNU Common Lisp не встречал.

Других свободно распространяемых (и при этом живых) реализаций Common Lisp я не нашёл.

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

Если что, я не настоящий сварщик лиспер. Так, интересуюсь чуть-чуть.

причём до какой-то приемлемой степени это удалось только с SBCL (сообщение permission denied напечатать можно, но оно выглядит так, как хочет интерпретатор, а не программист)

А дайте код посмотреть, пожалуйста, если не трудно. Интересно же.

CLISP мёртв, из

CLISP мёртв, из FreeBSD port collection его лет десять как удалили, причём, насколько я понял, по причине того, что в нём нашли критическую уязвимость, а фиксить её оказалось некому. Если что, мне самому он нравился больше всех (пока был жив), но увы.

Про CCL ничего сказать не могу, и, видимо, сейчас смотреть его не полезу. Глава про Common Lisp мне и так несуразно дорого обошлась (в плане времени).

GCL, как ни странно, есть в репозиториях Devuan (и, по-видимому, Debian, у них база репозиториев почти не различается).

Код на SBCL вот:

#!/usr/bin/sbcl --script

(defun do_it (file len)
    (let ((c (read-char file nil nil)))
        (cond
            ((eq c nil) t)
            ((eq c #\Newline) (prin1 len) (terpri) (do_it file 0))
            (t (do_it file (+ 1 len)))
        )
    )
)

(defun process_file (fname)
    (with-open-file (f fname :direction :input :if-does-not-exist nil)
        (if (null f)
            (progn
                (princ "Couldn't open the file" *error-output*) 
                (terpri *error-output*)
                nil
            )
            (do_it f 0)
        )
    )
)

(defun process_stdin ()
    (do_it *standard-input* 0)
)

(handler-case
    (if (cdr *posix-argv*)
        (process_file (second *posix-argv*))
        (process_stdin)
    )
    ;;
    (file-error (er)
        (princ er *error-output*)
        (terpri *error-output*)
    )
    (sb-sys:interactive-interrupt () nil)
)

Программа решает школьную задачку "читать поток до конца файла, печатать длины прочитанных строк"; если в командной строке ничего нет — читает из стандартного ввода, если же аргумент есть — открывает указанный файл и читает из него. Вся функциональность программы заключена в функции do_it, остальное — бессмысленная и беспощадная борьба с мракобесием создателей CL вообще и SBCL в частности.

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступны HTML теги: <a> <em> <strong> <ins> <del> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre>
  • Строки и параграфы переносятся автоматически.

Подробнее о форматировании

CAPTCHA
Проверка на бота
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.