В некоторых случаях неизменность вынуждает вас клонировать объект и должна выделять больше памяти. не занимает памяти, поскольку старые копии могут быть сброшены. Например, сборщик мусора в CLR хорошо справляется с этой ситуацией, так что это (как правило) не имеет большого значения.
Однако цепочка операций на самом деле не означает клонирование объекта. Это, безусловно, относится к функциональным спискам. Когда вы используете их обычным способом, вам нужно выделить ячейку памяти только для одного элемента (при добавлении элементов в начало списка).
Ваш пример с обработкой изображений также может быть реализован более эффективным способом. Я буду использовать синтаксис C #, чтобы код был легким для понимания без знания FP (но на обычном функциональном языке он выглядел бы лучше). Вместо того, чтобы на самом деле клонировать изображение, вы можете просто сохранить операции, которые вы хотите сделать с изображением. Например что-то вроде этого:
class Image {
Bitmap source;
FileFormat format;
float newWidth, newHeight;
float rotation;
// Public constructor to load the image from a file
public Image(string sourceFile) {
this.source = Bitmap.FromFile(sourceFile);
this.newWidth = this.source.Width;
this.newHeight = this.source.Height;
}
// Private constructor used by the 'cloning' methods
private Image(Bitmap s, float w, float h, float r, FileFormat fmt) {
source = s; newWidth = w; newHeight = h;
rotation = r; format = fmt;
}
// Methods that can be used for creating modified clones of
// the 'Image' value using method chaining - these methods only
// store operations that we need to do later
public Image Rotate(float r) {
return new Image(source, newWidth, newHeight, rotation + r, format);
}
public Image Resize(float w, float h) {
return new Image(source, w, h, rotation, format);
}
public Image ConvertTo(FileFormat fmt) {
return new Image(source, newWidth, newHeight, rotation, fmt);
}
public void SaveFile(string f) {
// process all the operations here and save the image
}
}
Класс на самом деле не создает клон всего растрового изображения каждый раз, когда вы вызываете метод. Он только отслеживает, что нужно сделать позже, когда вы наконец попытаетесь сохранить изображение. В следующем примере базовый Bitmap
будет создан только один раз:
var i = new Image("file.jpg");
i.Resize(500, 800).Rotate(90).ConvertTo(Gif).SaveFile("fileNew.gif");
Таким образом, код выглядит так, как будто вы клонируете объект и фактически создаете новую копию класса Image
каждый раз, когда вызываете какую-либо операцию. Однако это не означает, что операция требует больших затрат памяти - ее можно скрыть в функциональной библиотеке, которая может быть реализована всевозможными способами (но при этом сохраняется важная ссылочная прозрачность ).