In alcuni casi, l'immutabilità ti costringe a clonare l'oggetto e ha bisogno di allocare più memoria. Non è necessario occupare la memoria, perché le copie più vecchie possono essere scartate. Ad esempio, il garbage collector CLR gestisce abbastanza bene questa situazione, quindi non è (di solito) un grosso problema.
Tuttavia, il concatenamento di operazioni non significa in realtà la clonazione dell'oggetto. Questo è certamente il caso per gli elenchi funzionali. Quando li usi nel modo tipico, devi solo allocare una cella di memoria per un singolo elemento (quando aggiungi elementi in cima all'elenco).
L'esempio di elaborazione delle immagini può anche essere implementato in modo più efficiente. Userò la sintassi C# per mantenere il codice di facile comprensione senza conoscere FP (ma apparirebbe migliore in un linguaggio funzionale usuale). Invece di clonare effettivamente l'immagine, puoi semplicemente memorizzare le operazioni che vuoi fare con l'immagine. Per esempio qualcosa di simile:
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
}
}
La classe non crea un clone di tutta la bitmap ogni volta che si richiama un metodo. Tiene solo traccia di ciò che deve essere fatto dopo, quando finalmente tenterai di salvare l'immagine.Nel seguente esempio, sarebbero creati una sola volta il sottostante Bitmap
:
var i = new Image("file.jpg");
i.Resize(500, 800).Rotate(90).ConvertTo(Gif).SaveFile("fileNew.gif");
In sintesi, il codice sembra che stai clonando l'oggetto e il gioco è in realtà la creazione di una nuova copia della classe Image
ogni volta che si chiama qualche operazione Tuttavia, ciò non significa che l'operazione sia costosa in termini di memoria - ciò può essere nascosto nella libreria funzionale, che può essere implementata in tutti i modi (ma conserva l'importante trasparenza referenziale ).
Penso che anche un oggetto con uno stato mutabile avrà bisogno sia di un buffer sorgente che di destinazione quando si muta un'immagine per trasformazioni più sostanziali, specialmente cose come 'Resize()' e 'Rotate()'. – msandiford
Scusa, non sono sicuro di aver capito la vecchia copia, il nuovo modo di pensare. È un oggetto più grande per ogni classe restituita dai metodi chainable, o è solo un extra per il singolo oggetto ("i" in questo caso). Se riesci a elaborare un po ', è molto apprezzato. – ciscoheat
Come si esegue una trasformazione dello spazio dei colori senza un'intera immagine temporanea? – Gabe