Я пытаюсь выяснить, как неразрушающее управление большим количеством реализовано в функциональном программировании, т.е. как возможно изменить или удалить единственные элементы, не имея необходимость создавать абсолютно новый набор, где все элементы, даже неизмененные, будут дублированы в памяти. (Даже если бы исходный набор был бы собран "мусор", я ожидал бы, что объем потребляемой памяти и общая производительность такого набора будут ужасны.)
Используя F#, я придумал функцию insert
это разделяет список на две части и представляет новый промежуток элемента, по-видимому не клонируя все неизменные элементы:
// return a list without its first n elements:
// (helper function)
let rec skip list n =
if n = 0 then
list
else
match list with
| [] -> []
| x::xs -> skip xs (n-1)
// return only the first n elements of a list:
// (helper function)
let rec take list n =
if n = 0 then
[]
else
match list with
| [] -> []
| x::xs -> x::(take xs (n-1))
// insert a value into a list at the specified zero-based position:
let insert list position value =
(take list position) @ [value] @ (skip list position)
Я тогда проверил, "переработаны" ли объекты из исходного списка в новых списках при помощи.NET Object.ReferenceEquals
:
open System
let (===) x y =
Object.ReferenceEquals(x, y)
let x = Some(42)
let L = [Some(0); x; Some(43)]
let M = Some(1) |> insert L 1
Следующие три выражения все оценивают к true
, указание, что значение, упомянутое x
снова используется оба в списках L
и M
, т.е. это там - только 1 копия этого значения в памяти:
L.[1] === x
M.[2] === x
L.[1] === M.[2]
Языки функционального программирования обычно снова используют значения вместо того, чтобы клонировать их к новой ячейке памяти, или я был просто удачлив с поведением F#? Принятие первого, это, как довольно эффективное памятью редактирование наборов может быть реализовано в функциональном программировании?
(Btw.: Я знаю о книге Chris Okasaki Чисто функциональные структуры данных, но еще не имел времени для чтения ее полностью.)