[ocaml] reference semantics
Изначально в ФЯ нет изменяемых данных, поэтому то, что '=' копирует именно ссылку - логично. Ссылку скопировать дешевле, а если нет разницы... Ну а когда потом в язык добавляются всякие эти Array и пр. получается вот так вот.
Допустим у меня есть некоторый сложный тип данных, внутри которого есть массив. И у меня создается большое количество объектов такого типа. Я хочу чтобы у каждого объекта этот массив был свой. В C++ для этого есть конструкторы копирования. А как быть в ML? Вдруг например, где-нибудь, массивы неявно скопируются по ссылке -- тогда операция с одним объектом испортит случайно данные другого объекта и отладить такую ошибку будет очень сложно.
В С++ большие объекты тоже обычно по ссылкам передаются. Поэтому более-менее с тем же успехом там тоже можно нечаяно попортить значение. Можешь привести пример неочевидной ошибки?
Более естественное представление --- это списки.
Если ты захотел массивы, значит, ты хочешь побыстрее
и должен знать, что делаешь.
Решение: не использовать Array.set или перед этим делать копирование.
Тем более, что даётся подсказка:
- : unit =
значит, мимо не пройдёшь.
---
...Я работаю антинаучным аферистом...
Вероятно, в питоне происходит то же самое.
copy.deepcopy
А если бы и были - то твой вопрос не имел бы смысла за отсутствием деструктивной операции set.
То есть желание использовать такие структуры возникло не из желания сделать побыстрее, а потому что такой тип больше соотвествует смыслу задачи.
В результате пока заменил на список пар. Все вроде работает, но imho идеологически не очень правильно: список здесь лишний, в исходной задаче нет никакого списка. Есть конечное отображение из A в B. Разница примерно такая же, как между std::set и std::list. Возникают вопросы типа: если есть пары (a,b1) и (a,b2 то которое значение использовать? Хотелось чтобы сам тип данных не допускал появления подобных неоднозначностей (как например std::map). Непонятно, почему столь естественный и интуитивно понятный тип данных отсутствует в языке как встроенный, и приходится эмулировать его с помощью списка пар.
Ну и нормально. Hashtbl - это императивная библиотека (в ocaml вообще в стандартной библиотеке чисто функциональных модулей мало). Поэтому всё просто: хочешь копировать - используй функцию copy, а оператор let подразумевает создание псевдонима, а не копирование.
![](/images/graemlins/confused.gif)
Я думаю хэш таблицы в этом языке тоже есть
Кста, не знаю как в caml-е но в SML есть стандартная библиотека отображений на бинарных деревьях, так она вся из себя аппликативная, то есть в ней нет понятия с-update-ить отображение, только создать новое.
в ocaml есть map с чисто функциональной сигнатурой
![](/images/graemlins/ooo.gif)
Вопрос решен. Всем ответившим - большое спасибо!
PS. Работа с массивами и хэш-таблицами все равно не до конца понятна. Правильно ли я понимаю, что если я пишу программу в функциональном стиле, то все структуры данных тоже должны быть чисто функциональными? И если я пытаюсь использовать какой-нибудь Array или Hashtbl, то получаю мощный геморрой с тем, что нужно постоянно следить, кто где что поменял, кто где делает копии, а кто не делает итп?
> Благо ML язык высшего порядка.
Если ты предлагаешь использовать функции типа A -> B, то здесь это не подходит, так как с ними нужно делать действия типа:
1) сравнивать
2) находить область определения
3) сохранять в файл, читать из файла
Для Array, Hashtbl это просто делается. Как сравнивать абстрактные функции или записывать их в файл --- непонятно.
> то все структуры данных тоже должны быть чисто функциональными?
Я бы сказал, что желательно, но не обязательно.
> И если я пытаюсь использовать какой-нибудь Array или Hashtbl,
> то получаю мощный геморрой с тем, что нужно постоянно следить,
> кто где что поменял, кто где делает копии, а кто не делает итп?
Негде сейчас проверить, но разве настолько сложно отследить использование выражений с unit?
По-моему, должно быть достаточно усвоить, что let --- это bind или alias, а не copy.
То есть, если ты хочешь создать именно новый объект, то ты используешь copy, в остальных случаях --- let
(раз программа в функциональном стиле, то достаточно нового имени).
---
...Я работаю...
> То есть, если ты хочешь создать именно новый объект, то ты используешь copy, в остальных
> случаях --- let
В общих чертах понял. Спасибо!
Оставить комментарий
Landstreicher
Раньше думал, что в ML используется value semantics, а не reference semantics. Оказалось не так:Почему так сделано? В C++ работает по-другому (и на мой взгляд, более логично).
Мне казалось, в функциональных языках значения обычно определяются один раз и потоэму любые изменения создают копию.