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

Действительно, в OCaml тоже есть. Затупил, не сразу заметил. Читал какие-то факи и туториалы, там были List и Hashtbl, а Map не было.
Вопрос решен. Всем ответившим - большое спасибо!
PS. Работа с массивами и хэш-таблицами все равно не до конца понятна. Правильно ли я понимаю, что если я пишу программу в функциональном стиле, то все структуры данных тоже должны быть чисто функциональными? И если я пытаюсь использовать какой-нибудь Array или Hashtbl, то получаю мощный геморрой с тем, что нужно постоянно следить, кто где что поменял, кто где делает копии, а кто не делает итп?
Вопрос решен. Всем ответившим - большое спасибо!
PS. Работа с массивами и хэш-таблицами все равно не до конца понятна. Правильно ли я понимаю, что если я пишу программу в функциональном стиле, то все структуры данных тоже должны быть чисто функциональными? И если я пытаюсь использовать какой-нибудь Array или Hashtbl, то получаю мощный геморрой с тем, что нужно постоянно следить, кто где что поменял, кто где делает копии, а кто не делает итп?
> Если по смыслу задачи нужно отображение, почему бы не воспользоваться отображением
> Благо ML язык высшего порядка.
Если ты предлагаешь использовать функции типа A -> B, то здесь это не подходит, так как с ними нужно делать действия типа:
1) сравнивать
2) находить область определения
3) сохранять в файл, читать из файла
Для Array, Hashtbl это просто делается. Как сравнивать абстрактные функции или записывать их в файл --- непонятно.
> Благо ML язык высшего порядка.
Если ты предлагаешь использовать функции типа A -> B, то здесь это не подходит, так как с ними нужно делать действия типа:
1) сравнивать
2) находить область определения
3) сохранять в файл, читать из файла
Для Array, Hashtbl это просто делается. Как сравнивать абстрактные функции или записывать их в файл --- непонятно.
> Правильно ли я понимаю, что если я пишу программу в функциональном стиле,
> то все структуры данных тоже должны быть чисто функциональными?
Я бы сказал, что желательно, но не обязательно.
> И если я пытаюсь использовать какой-нибудь Array или Hashtbl,
> то получаю мощный геморрой с тем, что нужно постоянно следить,
> кто где что поменял, кто где делает копии, а кто не делает итп?
Негде сейчас проверить, но разве настолько сложно отследить использование выражений с unit?
По-моему, должно быть достаточно усвоить, что let --- это bind или alias, а не copy.
То есть, если ты хочешь создать именно новый объект, то ты используешь copy, в остальных случаях --- let
(раз программа в функциональном стиле, то достаточно нового имени).
---
...Я работаю...
> то все структуры данных тоже должны быть чисто функциональными?
Я бы сказал, что желательно, но не обязательно.
> И если я пытаюсь использовать какой-нибудь Array или Hashtbl,
> то получаю мощный геморрой с тем, что нужно постоянно следить,
> кто где что поменял, кто где делает копии, а кто не делает итп?
Негде сейчас проверить, но разве настолько сложно отследить использование выражений с unit?
По-моему, должно быть достаточно усвоить, что let --- это bind или alias, а не copy.
То есть, если ты хочешь создать именно новый объект, то ты используешь copy, в остальных случаях --- let
(раз программа в функциональном стиле, то достаточно нового имени).
---
...Я работаю...
> По-моему, должно быть достаточно усвоить, что let --- это bind или alias, а не copy.
> То есть, если ты хочешь создать именно новый объект, то ты используешь copy, в остальных
> случаях --- let
В общих чертах понял. Спасибо!
> То есть, если ты хочешь создать именно новый объект, то ты используешь copy, в остальных
> случаях --- let
В общих чертах понял. Спасибо!
Оставить комментарий
Landstreicher
Раньше думал, что в ML используется value semantics, а не reference semantics. Оказалось не так:Почему так сделано? В C++ работает по-другому (и на мой взгляд, более логично).
Мне казалось, в функциональных языках значения обычно определяются один раз и потоэму любые изменения создают копию.