передача копированием происходит только для очень простых объектов, таких как числа, либо при явном копировании (copy-list, copy-alist, copy-tree, copy-seq, alexandria:copy-array, ...).
А как тогда передать копию объекта? Нужно для каждого уникального объекта писать и вызывать функцию копирования? Или компилятор умеет сам создавать копии объектов бит в бит.
Поведение как в С++: f(obj) - копия объекта, f(&obj) - ссылка.
То есть нужен макрос my-defun чтобы писать (my-defun f ((ref x) (copy y))? Тогда нужно запомнить сигнатуру f по части ref/copy и сделать соответствующий (call f x y) — пусть смотрит на эту сигнатуру и пишет код который смотрит на объект, пытается сделать гарантированную ссылку или копию и бросает исключение если не может.
Во первых непонятно, как в лиспе тогда пишут в функциональном стиле, когда все объекты CLOS передаются по ссылке. И как решить такую задачу: передать в функцию копию произвольного объекта, изменить несколько слотов и вернуть этот объект.
Понял как спросить. Есть ли в Lisp обобщенный копирующий конструктор по умолчанию, который умеет копировать инстанс объекта бит в бит, или копирующий конструктор мне надо реализовывать самому для каждого моего класса?
Типа
(defmetod copy-obj ((obj my-obj)))
(f (copy-obj my-obj)) - передача объекта по значению
А простая копия структуры в лиспе делается в месте вызова с помощью (f (copy-struct-name obj)) вместо декларации bitcopy в месте определения функции и перепоручения делать copy в месте вызова компилятору (как оно в плюсах) — стратегия копирования может быть разной (просто copy-btree или полное copy/btree, например), её выбирает «клиент».
Хочу познакомиться с функциональным языком. Lisp мне показался самым простым и система установки библиотек quicklisp очень сильно помогает. Имею некоторы опыт программирования на С++.
В плюсах стратегия тоже может быть разной, просто надо самому определить нужный конструктор копирования и компилятор будет его использовать сам, что очень удобно.
Haskell слишком замороченный. Там очень плохо развита диагностика ошибок, очень сложно понять в каком месте возникла ошибка. А так, влияние ЛОРа по части Lisp имеет место.
Т.е. тебе нужен не «функциональный язык», а модный, нонконформистский и илитарный, про который ты начитался на ЛОРе. Что ж, с одной стороны жалко, что ты потратишь некоторую часть молодости на изучение в общем бесполезной и бесперспективной технологии. Лучшим программистом это тебя тоже не сделает.
Зато, может быть, на своей шкуре поймёшь, что надо поменьше доверять ЛОРовским троллям, и побольше думать головой. Удачи.
Я хочу составить собственное мнение. Познакомиться с языком, еще не значит писать на нем всю жизнь. Многие вещи в Lisp мне очень нравяться: emacs, slime, quicklisp.
Ты хочешь копировать объекты, и хочешь писать в стиле ФП. Здесь есть противоречие. Когда пишут в стиле ФП, то данные обычно разделяют и не меняют их, да и передают их по ссылке (тут термины разные бывают, но в общем, лисп передает как надо). По умному такие данные называются persistent purely functional data.
Тут есть одна проблема с лиспом. Если ты не знаешь, как работать с такими данными, то Common Lisp тебя этому не научит, т.е. не будет бить по рукам, если ты сделаешь что-то не так. CL - очень гибкий и практичный инструмент, он послушно будет делать то, что ты ему скажешь. А потому как первый, как второй или даже как третий язык совершенно непригодный (хотя бывают исключения). Для обучения нужны более жесткие и менее компромиссные языки. В идеале, это даже могут быть языки одной парадигмы (haskell, smalltalk, си).
Haskell неоправданно переусложнен. К тому же там нет объекто-ориентированной парадигмы, и как следствие невозможность отделение интерфейса от реализации.
Это как? Пусть будет template <typename T> tree { ... и два вида копирования — shallow и deep. Писать два перегруженных/шаблонных по отношению к copy_strategy = shallow_copy или deep_copy (enum или пустые структуры) конструктора tree(tree<T> &)? Их можно написать? Как это скажется на обычном вызове f(tree<T>)? Всё равно проще сделать нормальные методы и выбор в месте вызова.
Понял как спросить. Есть ли в Lisp обобщенный копирующий конструктор по умолчанию, который умеет копировать инстанс объекта бит в бит, или копирующий конструктор мне надо реализовывать самому для каждого моего класса?
Нет. В CLOS (вернее, в metaobject protocol, на котором CLOS написан) есть достаточное количество интроспекции, чтобы разобрать объект и собрать его копию. Это можешь написать в качестве начального знакомства с MOP. Для последовательностей есть copy-seq. Тип объекта определяется в рантайме.
Зато в F# и Scala ООП на полную катушку. Впрочем, твое утверждение неверно. ООП не связано напрямую с разледением интерфейса от реализации. В том же Haskell есть и модули, и тайпклассы.
Ладно, видно, что до MOP я еще не дозрел. Есть еще вопрос, как экспортировать из пакета символы всех акцессоров класса? Я надеялся что :export :class-name будет достаточно, но не получается.
Нет в CLOS акцессоров. Есть обобщённые функции и их специализации.
Некоторые так делают, но я считаю это дурным тоном. Секция :exports пакета определяет публичный интерфейс. Если экспорты будут разбросаны по коду, то это затруднит его чтение и понимание.