2016-04-25 3 views
2

Wie leitet F # Daten von einer Aufruferfunktion an eine aufgerufene Funktion weiter? Macht es eine Kopie der Daten, bevor es übergeben wird, oder gibt es nur einen Zeiger? Ich würde mir letzteres überlegen aber dafür sorgen wollen. Zu einem verwandten Hinweis, gibt es Auswirkungen auf die Leistung der folgenden 2 F # -Code-Stile.Auswirkungen der F # -Effizienz beim Übergeben großer Datenstrukturen zwischen Funktionen

let someFunction e = 
    1//pretend this is a complicated function 

let someOtherFunction e = 
    2//pretend this is a complicated function 

let foo f largeList= 
    List.map (fun elem -> f elem) 

let bar largeList = 
    largeList 
    |> foo someFunction 
    |> foo someOtherFunction 


let bar2 largeList = 
    let foo2 f f2 = 
     largeList 
     |> List.map (fun elem -> f elem) 
     |> List.map (fun elem -> f2 elem) 
    foo2 someFunction someOtherFunction 

Würden Sie erwarten, dass bar eine andere Leistung als bar2 hat? Wenn nicht, gibt es Situationen, die mir bewusst sein sollten, dass dies einen Unterschied machen würde?

+5

Strukturen werden nach Wert übergeben, Klassen nach Referenz bar2 kann geringfügig schneller sein, aber der Unterschied wäre sehr klein - einfach messen –

+4

https://ericlippert.com/2012/12/17/performance-rant –

Antwort

3

Die kurze Antwort:

Nr Die gesamte Liste nicht kopiert wird, nur der Verweis auf sie ist.

Die lange Antwort:

In F # (wie gerade in C#) sowohl Wert und Referenztypen können entweder als Wert oder als Referenz übergeben werden.

Sowohl Werttypen als auch Referenztypen werden standardmäßig als Wert übergeben.

  • Im Fall von Werttypen (structs) bedeutet dies, dass Sie um eine Kopie der gesamten Datenstruktur vorbei sein werden.

  • Bei Referenztypen (Klassen, diskriminierte Verschaltungen, Aufzeichnungen usw.) bedeutet dies, dass die Referenz als Wert übergeben wird. Dies bedeutet nicht, dass die gesamte Datenstruktur kopiert wird, sondern lediglich dass ein int/int64 Verweis auf die Datenstruktur kopiert wird.

Wenn Sie mit veränderbaren Datenstrukturen arbeiten, z. ResizeArray<'T> (. NET List<'T>), die Klassen sind, die Weitergabe von Referenzen nach Wert könnte Auswirkungen haben. Vielleicht fügt die Funktion, an die Sie sie übergeben haben, Elemente zur Liste hinzu? Eine solche Aktualisierung würde für die Datenstruktur gelten, auf die von beiden Standorten verwiesen wird. Da Ihre Frage jedoch die unveränderliche F # -Liste verwendet, müssen Sie sich darüber keine Gedanken machen!

Sie können auch Wert/Referenztypen Bezug genommen wird, für weitere Details sehen, dass passieren: https://msdn.microsoft.com/en-us/library/dd233213.aspx#Anchor_4

F # Liste wird als einfach verkettete Liste implementiert, dass Mittel, die den Kopf und prepend Operationen O Zugriff (1). Diese Datenstrukturen sind auch sehr speichereffizient, denn wenn Sie ein Element der Liste voranstellen, müssen Sie nur den neuen Wert und einen Verweis auf den Rest der Liste speichern.

Sie können also sehen, wie es funktioniert, wie eine Datenstruktur, wie diese umgesetzt werden kann:

type ExampleList<'T> = 
    |Empty 
    |Cons of 'T * List<'T> 

Weitere Informationen:

List.map eifrig Sinn ausgewertet wird, dass jedes Mal, wenn Sie es nennen, Eine neue Liste wird erstellt. Wenn Sie Seq.map verwenden (F # List implementiert die Schnittstelle IEnumerable<'T>), die faul ausgewertet wird, können Sie beide Zuordnungsoperationen nur in der Aufzählung der Liste auswerten.

largeList 
|> Seq.map (fun elem -> f elem) 
|> Seq.map (fun elem -> f2 elem) 
|> List.ofSeq 

Dies ist wahrscheinlich viel effizienter für große Listen sein, weil es handelt sich nur um eine neue Liste der Ergebnisse Zuteilung, anstatt zwei.

Verwandte Themen