Satzart Inferenz

8

Im folgenden Codefragment

%Vor%

Die Zeile mit dem Kommentar wird nicht kompiliert. Aus irgendeinem Grund kann der Typüberprüfer nicht herausfinden, dass der Typ für p1 myrec1 sein sollte. Liegt es daran, dass dieser Fall der Typinferenz einfach unlösbar ist oder nur eine Einschränkung der F # -Typinferenz ist?

    
Max 04.04.2013, 13:25
quelle

4 Antworten

9

Von hier :

  

Die Beschriftungen des zuletzt deklarierten Typs haben Vorrang vor   diejenigen des zuvor angegebenen Typs

Also wenn du es so machst:

%Vor%

dann wird es funktionieren.

Für Ihr Lesevergnügen von hier ( die F # 3.0 Spezifikation):

%Vor%

6.3.5 Record Expressions

In diesem Fall ist unser Feldinitialisierer kein einzelner Bezeichner, daher verwendet er "Feldbezeichnerauflösung" von 14.1.9.

  

Jedes field-initialiseri hat das form field-labeli = expri. Jedes Feld-Labeli ist ein Long-Ident, das muss   Auflösen in ein Feld Fi in einem eindeutigen Datensatztyp R wie folgt:

     

· Wenn field-labeli ein einzelner Bezeichner fld und die Initiale ist   Typ ist bekanntermaßen ein Datensatztyp R & lt; em>, ..., & gt; das hat field Fi mit   name fld, dann wird die Feldbezeichnung in Fi aufgelöst.

     

· Wenn field-labeli kein einzelner Bezeichner oder der erste Bezeichner ist   type ist ein Variablentyp, dann wird die Feldbezeichnung durch aufgelöst   Durchführen einer Feldbeschriftungsauflösung (siehe §14.1) für Feldbezeichnungen. Dies   Prozedur führt zu einer Reihe von Feldern FSeti. Jedes Element dieses Sets   hat einen entsprechenden Satztyp, was zu einem Datensatz führt   Typen RSeti. Die Schnittmenge aller RSeti muss einen einzelnen Datensatz ergeben   Geben Sie R ein, und jedes Feld wird dann in das entsprechende Feld in R aufgelöst.

14.1.9 Feldbeschriftungsauflösung

Unser long-ident ist ein FieldLabel, daher wird es mit der in 8.4.2 beschriebenen Tabelle FieldLabels gesucht.

  

Feldlabelauflösung gibt an, wie Identifikatoren wie Feld1 in {field1 = expr; ... feldN =   Ausdruck}. Die Feldkennsatzauflösung führt die folgenden Schritte durch:

     

1. Suchen Sie alle Felder in allen verfügbaren Typen in der Typen Tabelle und der FieldLabels-Tabelle (§ 8.4.2).

     

2. Liefert den Satz von Felddeklarationen.

8.4.2 Namensauflösung und Datensatzfeldbeschriftungen

Wie hier erwähnt, wird die FieldLabels-Tabelle in der Namensauflösung für Mitglieder (14.1) verwendet.

  

Für einen Datensatztyp werden die Datensatzfeldbezeichnungen Feld1 ... FeldN hinzugefügt   in die FieldLabels-Tabelle der aktuellen Namensauflösungsumgebung   Es sei denn, der Datensatztyp verfügt über das RequireQualifiedAccess-Attribut.   Feldbezeichnungen in der FieldLabels - Tabelle spielen eine besondere Rolle in   Namensauflösung für Mitglieder (§14.1): Der Typ eines Ausdrucks kann sein   von einem Plattenlabel abgeleitet. Zum Beispiel: Geben Sie R = {dx: int; dy:   int} sei f x = x.dx // x wird als Typ R bezeichnet In diesem Beispiel   Das Nachschlagen .dx wird aufgelöst, um eine Feldsuche zu sein.

14.1.4Name Auflösung in Ausdrücken Dieser Abschnitt scheint etwas unscharf zu sein, aber ich denke, dass er an dieser Stelle die Namensauflösung verwendet. Wie am Ende bemerkt, gib das erste Element zurück, wenn es mehr als eins gibt.

  

Gegeben ist eine Eingabe long-ident, Umgebung env und eine optionale Anzahl n von   die Anzahl der nachfolgenden Typargumente & lt; , ..., & gt ;, Namensauflösung in   Expressions berechnet ein Ergebnis, das die Interpretation des   long-ident & lt; , ..., & gt; Präfix als Wert oder anderes Ausdruckselement und a   Restweg Rest. Wie die Namensauflösung in Expressions verläuft, hängt davon ab   ob long-ident ein einzelner Bezeichner ist oder aus mehr besteht   als eine Kennung. Wenn long-ident eine einzige ID ist:

     

1. Suchen Sie in der Tabelle "ExprItems" nach ident. Gib das Ergebnis zurück und leere Pause.

     

2. Wenn ident nicht in der Tabelle "ExprItems" angezeigt wird, suchen Sie in der Tabelle "Types" nach einer generischen Arity, die mit n übereinstimmt, sofern sie verfügbar ist.   Gebe diesen Typ zurück und leere den Rest.

     

3. Wenn Ident nicht in der Tabelle "ExprItems" oder in der Tabelle "Types" angezeigt wird, schlagen Sie fehl.

     

...

     

Enthält der Ausdruck Mehrdeutigkeiten, Namensauflösung in Ausdrücken   gibt das erste Ergebnis zurück, das der Prozess generiert.

Der Teil, an dem Sie interessiert sind, ist die letzte Zeile oben: "gibt das erste Ergebnis zurück, das der Prozess generiert".

    
mydogisbox 04.04.2013, 13:46
quelle
4

Dieses Verhalten ist beabsichtigt. Ich kann nicht sagen, ob es eine Beschränkung der Typinferenz von F # oder eine Beschränkung von Typinferenzalgorithmen im Allgemeinen ist; Wenn Sie darüber nachdenken, gibt es zwei Möglichkeiten:

  1. Geben Sie für einen Record-Ausdruck {x = 1; y = 1} die Felder 'x' und 'y' für den letzten Typ an, um einen der beiden zu deklarieren. Dies ist am einfachsten zu verstehen, und der F # -Compiler implementiert die Inferenz des Datensatztyps.

  2. Versuchen Sie, die beste Anpassung basierend auf den Feldern der Typen im aktuellen Bereich zu ermitteln. (Ich denke, das ist das, worüber du fragst.)

    Dieser Algorithmus könnte jedoch zu anderen Problemen führen; Speziell für einen Datensatzausdruck {x = 1; y = 1} kann der Compiler nicht feststellen, ob Sie einen Ausdruck vom Typ myrec1 erstellen wollten, oder ob Sie einen Ausdruck von myrec2 erstellen wollten und Sie vergessen hatten, dem% einen Wert zuzuweisen. co_de% -Feld.

    Was sollte der Compiler auch tun, wenn Sie zwei Typen mit genau denselben Feldern deklarieren? Zum Beispiel, wenn Sie hinzufügen:

    %Vor%

Mit anderen Worten, gibt es kein kostenloses Mittagessen - Sie können die "Macht" der Typinferenz erhöhen, aber es kostet Sie einige Genauigkeit in der Fehlerdiagnose Sie Holen Sie sich vom Compiler.

    
Jack P. 04.04.2013 13:46
quelle
4

Wenn Sie Datensatztypen mit ähnlich benannten Feldern erstellen möchten, können Sie folgendermaßen unterscheiden:

%Vor%     
Robert Jeppesen 04.04.2013 14:05
quelle
1

Da es keine Typ-Annotationen gibt, leitet der Compiler den Record-Typ von den Labels ab, aber diejenigen des ersten Typs unterscheiden sich nicht ausreichend von den Labels des zweiten, so dass letzterer Vorrang hat und p1 vom Typ myrec2 ist. Verwenden Sie verschiedene Beschriftungen, um Typanmerkungen zu vermeiden und das erwartete Inferenzverhalten zu erhalten:

%Vor%     
Taha 04.04.2013 13:47
quelle

Tags und Links