In F # ist es möglich, einen Verweis auf einen veränderbaren, voreingestellten Wert als Parameter zu übergeben?

8

Für das Projekt Froto (Google Protobuf in F #) versuche ich, den Deserialisierungscode mithilfe von 'a ref objects zu aktualisieren Übergeben der Werte byref<'a> für die Leistung.

Der folgende Code schlägt jedoch in der Zeile hydrator &element field fehl:

%Vor%
  

Fehler FS0421: Die Adresse der Variablen 'Element' kann an dieser Stelle nicht verwendet werden

Gibt es etwas, was ich tun kann, damit dieser Code funktioniert, ohne die Signatur des Parameters hydrator zu ändern?

Mir ist sehr bewusst, dass ich hydrator:'a ref -> Field -> unit verwenden und die Dinge zum Laufen bringen kann. Das Ziel besteht jedoch darin, die Deserialisierung in record -Typen zu unterstützen, ohne bei jeder Deserialisierung eines Datensatzes einen Haufen ref -Objekte im Heap erstellen zu müssen.

Beachten Sie, dass der folgende Code vollkommen legal ist und die gleiche Signatur wie die obige hydrator -Funktionsdeklaration aufweist. Daher ist das Problem unklar.

%Vor%     
James Hugard 07.03.2016, 16:48
quelle

1 Antwort

6

Ich werde versuchen, klarzustellen, was ich in meinen Kommentaren gesagt habe. Du hast Recht, dass deine Definition von assign vollkommen in Ordnung ist und es erscheint , die Signatur byref<'a> -> 'a -> unit zu haben. Wenn Sie sich jedoch die resultierende Assembly ansehen, werden Sie feststellen, dass die Art der Kompilierung auf der .NET-Darstellungsebene lautet:

%Vor%

(Das heißt, es ist eine Methode, die zwei Argumente entgegennimmt und nichts zurückgibt, keinen Funktionswert, der ein Argument akzeptiert und eine Funktion zurückgibt, die das nächste Argument übernimmt und einen Wert vom Typ unit - Compiler zurückgibt verwendet einige zusätzliche Metadaten, um zu bestimmen, wie die Methode tatsächlich deklariert wurde.)

Dasselbe gilt für Funktionsdefinitionen, die nicht byref enthalten. Angenommen, Sie haben die folgende Definition:

%Vor%

Dann erstellt der Compiler tatsächlich eine Methode mit der Signatur

%Vor%

Der Compiler ist schlau genug, um das Richtige zu tun, wenn Sie versuchen, eine Funktion wie someFunc als ersten Klassenwert zu verwenden - wenn Sie ihn in einem Kontext verwenden, in dem er nicht auf Argumente angewendet wird, wird der Compiler Generiere einen Subtyp von int -> string -> unit (was FSharpFunc<int, FSharpFunc<string, unit>> auf der .NET Repräsentationsebene ist), und alles funktioniert nahtlos.

Wenn Sie jedoch versuchen, das gleiche mit assign zu tun, wird es nicht funktionieren (oder nicht funktionieren, aber es gibt mehrere Compilerfehler, die den Eindruck erwecken, dass bestimmte Varianten funktionieren, wenn sie wirklich nicht funktionieren.) t - Sie erhalten möglicherweise keinen Compilerfehler, aber Sie erhalten möglicherweise eine Ausgabeassembly, die falsch formatiert ist. - Für .NET-Instantiierungen ist es nicht zulässig, byref types als generische Typargumente zu verwenden, damit FSharpFunc<int byref, FSharpFunc<int, unit>> nicht gültig ist. NET-Typ. Der grundlegende Weg, dass F # Funktionswerte darstellt, funktioniert nicht, wenn byref Argumente vorhanden sind.

Also besteht die Problemumgehung darin, einen eigenen Typ mit einer Methode zu erstellen, die ein byref -Argument verwendet und dann Untertypen / Instanzen mit dem gewünschten Verhalten erstellt, ähnlich wie manuell, was der Compiler automatisch in der nicht% co_de macht % Fall. Sie könnten dies mit einem benannten Typ tun

%Vor%

oder mit einem Delegattyp

%Vor%

Beachten Sie, dass beim Aufruf von Methoden wie byref für den Delegaten oder den Nominaltyp kein tatsächliches Tupel erstellt wird. Daher sollten Sie sich keine Gedanken über zusätzlichen Aufwand machen (es ist eine .NET-Methode, die zwei Argumente entgegennimmt und behandelt wird) als solche vom Compiler). Es gibt die Kosten eines Aufrufs einer virtuellen Methode oder eines Delegataufrufs, aber in den meisten Fällen liegen ähnliche Kosten bei der Verwendung von Funktionswerten auch in einer Klasse vor. Und im Allgemeinen sollten Sie, wenn Sie sich Sorgen um die Leistung machen, ein Ziel und eine Maßnahme dagegen setzen, anstatt zu versuchen, vorzeitig zu optimieren.

    
kvb 08.03.2016, 16:42
quelle

Tags und Links