LINUX.ORG.RU

Декларации immutable в Сommon Lisp

 


0

2

Всем привет!

КТо-нибудь встречался с попытками прикрутить ту или иную форму декларации const к Common lisp? Я думаю, что для этого нужно лезть в потроха самого компилятора. Меня интересуют в этой связи SBCL и CCL.

В простейшем случае декларация const должна распространяться на биндинг переменной и говорить о том, что в области действия биндинга не делается setq.

Более сложный вариант - заявление о неприкосновенности полей объекта. Например, пусть мы получили параметр cons. Тогда декларируем что-то типа (declare (const (car param))) и это значит, что мы не трогаем car param и полагаем, что у нас под рукой другие его тоже не трогают. Правда, тут есть нюансы смысла (мы не трогаем, другие не трогают, никто не трогает), но не суть. Мне бы хоть что-нибудь.

А то вишь - отец всех функциональных языков без иммутабельности...

★★★★★

Может кто-нибудь объяснит наконец почему отсутствие фичи - мутабельности преподносят как наличие некой фичи?

anonymous
()

Есть 2 соображения на этот счет. Во-первых, CL в основном используется одиночками, он не для широкомасштабной разработки. А если программист пишет все сам, то это ему и не нужно, нет смысла опасаться, что что-то будет изменено, поскольку когда он что-то делает, он должен будет знать, кто это будет использовать. Поэтому, если другие модули и объекты ничего не изменяют, значит никаких изменений опасаться и не нужно.

Во-вторых, вот это явный минус использования функций вообще, потому что если бы вместо (setcar foo) Вы использовали бы стиль сообщенийfoo.setcar то Вы просто могли бы переопределить setcar для конкретного объекта/структуры, таким образом, чтобы ничего не менялось молча, или с ошибкой, и вообще любое поведение

emergingOfTheHero
()

Вопрос, а нафига оно тебе? В языках, где есть const, наличие const добавляет возможностей для оптимизации компилятору. Соотв. тупая декларация const не даст тебе прироста в производительности, надо добавлять её в компилятор.

Если же тебе нужна гарантия иммутабельности, то бабахни геттер для свойства и дёргай только геттером его.

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

Если же тебе нужна гарантия иммутабельности, то бабахни геттер для свойства и дёргай только геттером его.

А какая это гарантия? Если ТС пишет все сам, то ему и не нужен никакой геттер, поскольку он знает, что этот объект изменять нельзя, соответственно, он и не будет его изменять. Поэтому, тут явно выражено опасение, что изменит кто-то другой. Но этот кто-то другой ничего не знает об этом геттере, и точно также может изменить объект обычным способом

emergingOfTheHero
()

А почему просто не взять другой язык программирования? Уже есть очень даже подходящие, включая системного программирования, где иммутабельность идет из-коробки

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

А у меня такой вопрос: допустим есть Java проект и его поддерживать сел идиот. Какие гарантии что идиот не расх%^&ит к х#*& рабочую систему?

anonymous
()

КТо-нибудь встречался с попытками прикрутить ту или иную форму декларации const к Common lisp?

Что значит «ту или иную»? defconstant — это не вам не та, и не иная?

CL-USER> (defconstant my-constant 42)
MY-CONSTANT
CL-USER> my-constant
42
CL-USER> (setf my-constant nil)
; in: SETF MY-CONSTANT
;     (SETF MY-CONSTANT NIL)
; ==>
;   (SETQ MY-CONSTANT NIL)
; 
; caught ERROR:
;   MY-CONSTANT is a constant and thus can't be set.
; 
; compilation unit finished
;   caught 1 ERROR condition
Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)

В простейшем случае декларация const должна распространяться на биндинг переменной и говорить о том, что в области действия биндинга не делается setq.

Это можно. Типа

(defmacro with-const (var &body body)
  (if (walk-find `(setq ,var) (macroexpand body))
      `(error "not const" ,var)
      body))

Более сложный вариант - заявление о неприкосновенности полей объекта.

А это в общем случае нельзя. Так как изменить поле может любая функция, в которую передан объект. Или придётся городить систему «типов», запрещая все вызовы, где не указано, что параметр не меняется. Но такая система запретит приведёт к тому, что

(defun read-car (x)
  (with-const (car x)
    (list x 1)))
является некорректным, так как функция list не указывает, что обязуется не менять поле car своего первого параметра.

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

Может кто-нибудь объяснит наконец почему отсутствие фичи - мутабельности преподносят как наличие некой фичи?

Дык, обычно это не отсутствие мутабельности вообще, а опциональное отсутствие мутабельности - вполне себе фича.

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

Но walk-find ведь нужно написать, я правильно понял? Это не так уж тривиально, поскольку некоторые вещи могут при макрорасширении не расширяться в setq, а расширяться в зависящие от реализации примитивы. Вроде в Screamer-е про это что-то было сказано.

Т.е. нужен либо «портативный компилятор лиспа в лисп», умеющий выявить все setq, либо умение лазить в кишки существующих компиляторов.

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

функция list не указывает

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

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

defconstant позволяет определять только глобальные константы. А в Си есть параметры const.

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

Но walk-find ведь нужно написать, я правильно понял? Это не так уж тривиально

Есть готовые

поскольку некоторые вещи могут при макрорасширении не расширяться в setq, а расширяться в зависящие от реализации примитивы

Не могут. Если в конце функция, то она не может менять свои параметры, если макрос, то он распакуется, из специальных форм меняет параметр только setq.

Другое дело, что надо лепить кучу костылей для обхода отсутствия гигиены. Иначе

(defun test (x)
  (with-const x
    (let ((x 2))
      (setq x 3))))
будет давать ошибку.

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

для примитивов нужны аннотации, написанные руками, это тоже проблема

Мало того, надо ещё и придумать формат аннотаций, чтобы сочетался с &key &rest и прочим...

monk ★★★★★
()

sbcl это и так понимает, емнип, без всяких деклараций

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

Вопрос, а нафига оно тебе? В языках, где есть const, наличие const добавляет возможностей для оптимизации компилятору

В первую очередь это дает типобезопасность, а потом всё остальное.

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

Ты сам-то подумал, что это тебе даст? В том же C запись в const переменную даст compile-time error. А тут что это даст? Трудноуловимую ошибку в рантайме? Просто збс. Я фигею от людей, которые в лисп прут то, с принципиальным отсутствием чего он писался изначально

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

Какие готовые есть? Я не знаю идеальных. В SBCL есть собственный walk, также есть в iterate и в screamer. Ни один из них не идеален. В arnesi точно есть баги, cl-cont под LGPL и мне не подходит.

Могут быть встроенные специальные формы, не предусмотренные стандартом. Они не являются макросами и не раскроются в функции. Честно сказать, я не помню деталей, но в скримере было на это указание.

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

Плюсую этого оратора. Без поддержки оптимизации компилятором const значений ты только устроишь себе лишний геморрой с макросами. Используй обычный геттер.

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

Я фигею от людей, которые в лисп прут то, с принципиальным отсутствием чего он писался изначально

Но с каким ЯВУ ещё возможно пытаться изменить его на столько, чтобы преодолевать «изначальные принципы»? ))

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

Собственно, тут надо исходить из того, что программист в CL имеет доступ только к изменению исходного кода, или AST, существенно изменить рантайм языка он не может, поэтому странно говорить о каких то особенных возможностях в данном контексте

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

CL в этом смысле далеко не самый гибкий
существенно изменить рантайм языка он не может

Сейчас пойдут сказки про JavaScript и Io. Анонiмус, ты близок к разоблачению.

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

Я фигею от людей, которые в лисп прут то, с принципиальным отсутствием чего он писался изначально

Так у него все посты такие) Я больше офигеваю, что многие на серьезе это обсуждают.

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

Зависит от реализации. В том-же SBCL собственно рантайм тебе нужен (в пределе) только в качестве того самого «компилятора» (да и то, если захочешь, только на начальном этапе), а дальше «дёргать» можешь хоть что угодно, благо и апи компилятора торчит наружу, и ffi «в полный рост». И всё это в пределах «одного файла»

Может CL (читай sbcl) и не самый гибкий, но «самый быстрый из самых гибких»

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

Даже без прироста в производительности прирост в понятности имеет смысл

Для понятности достаточно оставить комментарий.

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

Старинные лиспы славились тем, что давали свободный доступ к модификации интерпретатора изнутри рантайма языка, вот это и есть высший пилотаж лиспера, а CL уже не торт

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

В этом был даже какой-то философский, что-ли, смысл, философия лиспа, так сказать. Там неявно маячила идея ИИ, ибо мозг на том и основан, что он постоянно меняет сам себя

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

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

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

В этом был...

Поздно пить Боржоми. Мало ли что и когда было?

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

Без разницы, на каком языке реализован такой интерпретатор, на CL или нет.

такой скоростью

Для высокоуровнего языка скорость не имеет почти никакого значения

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

Для высокоуровнего языка скорость не имеет почти никакого значения

Для языка - нет (по определению). Для пользователей программ на таких языках - очень даже.

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

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

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

Анонiмус, ты близок к разоблачению.

emergingOfTheHero:

Старинные лиспы славились тем, что давали свободный доступ к модификации интерпретатора изнутри рантайма языка, вот это и есть высший пилотаж лиспера, а CL уже не торт

О да, оно. Давненько анонiмуса не было.

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

Он хрень написал. SBCL и так в состоянии сделать все необходимые оптимизации и без явного объявления. Суть конста в типобезопасности, const-correctness, а не в оптимизации

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

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

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

В том же C запись в const переменную даст compile-time error. А тут что это даст?

В лиспе почти все проверки в рантайме. Для проверок в compile-time я уже писал: надо делать систему типов для переменных (а не для значений). Получится что-то вроде Typed Racket.

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

Не понял, о чём ты. Конкретно в SBCL полно проверок в компайл-тайме, в т.ч. с выводом типов. declare для переменной выдаст ошибку или ворнинг в компайл-тайме, если компилятор увидит, что ты пытаешься записать в неё несовместимый тип. Например в этом коде SBCL увидит две ошибки типов (вторую увидит после исправления первой). Чем это не система типов дя переменных?

(proclaim '(ftype (function (integer string) t) ЮЮ))

(defun ЮЮ (ч с)
  (declare (integer ч))
  (setf ч "буль")
  ч
  )

(defun ЪЪ ()
  (ЮЮ "А" 1))

Какой коде волкер посоветуешь?

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

Конкретно в SBCL полно проверок в компайл-тайме, в т.ч. с выводом типов.

Верно. Но эта система нерасширяема. Для расширения нужно делать свой синтаксический анализатор и втыкать его вместо cl:compile и cl:compile-file.

Какой коде волкер посоветуешь?

https://github.com/sbcl/sbcl/blob/master/src/pcl/walk.lisp

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

Конкретно в SBCL

А если конкретно в SBCL, то можно форкнуть компилятор и расширить внутреннюю систему типов. Будет свой «CL с const».

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

Ну ладно, что в SBCL есть walker, я и раньше знал, а меня интересует ещё и CCL. Не думаю, что SBCL-ный подойдёт (он ссылается на внутренние ф-ии SBCL). В том-то и вопрос.

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

Но видимо, придётся делать что-то подобное: сделать библоитеку для SBCL и CCL, поменяв что-то в начинке компилятора (в идеале удастся обойтись без форка, а что-нибудь только продекорировать, хотя это получается не всегда).

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