2014-02-05 11 views
9

Die F # Tutorial den folgenden Ausschnitt umfasst:Anonym Satzart innerhalb Vereinigung diskriminiert

/// A record for a person's first and last name 
type Person = {  
    First : string 
    Last : string 
} 

/// define a discriminated union of 3 different kinds of employees 
type Employee = 
    | Engineer of Person 
    | Manager of Person * list<Employee>   // manager has list of reports 
    | Executive of Person * list<Employee> * Employee // executive also has an assistant 

Die Tatsache, dass Manager, und Vorstand wie beschrieben Tupeln beleidigt meine Empfindlichkeiten (ich leicht beleidigt bin). Es erscheint mir nicht besonders ausdrucksstark. Ich habe versucht, sie wie folgt zu ändern:

/// define a discriminated union of 3 different kinds of employees 
type Employee = 
    | Engineer of Person 
    | Manager of { Name: Person; Reports: Employee list }   // manager has list of reports 
    | Executive of { Name: Person; Reports: Employee list; Assistant: Employee} // executive also has an assistant 

Leider sind die Definitionen von Manager und Vorstand nun einen Fehler geben: „Dieses Konstrukt ist veraltet, betrachten, anstatt einen separaten Datensatztyp mit“ Ok, scheint fair, nennen wir es ManagerType. Aber warten Sie ... ManagerType bezieht sich auf Employee (für den Berichtsteil), und Employee verweist auf ManagerType (für die Manager-Option).

Gibt es hier eine Lösung? Ist es nicht möglich, zwei Datenstrukturen in Bezug aufeinander zu definieren?

Antwort

10

Sie können festlegen, voneinander abhängige Typen mit and:

type Employee = 
    | Engineer of Person 
    | Manager of Manager   // manager has list of reports 
    | Executive of Executive 
    and Manager = { Name: Person; Reports: Employee list } 
    and Executive = { Name: Person; Reports: Employee list; Assistant: Employee } 
+0

Interessant. Können wir auch die Vererbung verwenden? Kann Executive von Manager abgeleitet werden? Oder funktioniert das nur mit Records? –

10

Wenn Sie mit F # v3.1 können Sie named union fields [MSDN] verwenden (und schützen Sie Ihre zarte Sensibilität):

type Employee = 
    | Engineer of Person 
    | Manager of Name: Person * Reports: Employee list 
    | Executive of Name: Person * Reports: Employee list * Assistant: Employee 
+1

Diese Lösung i Es ist nicht schlecht (es vermeidet meine schwache Verfassung), aber wie würde es aussehen in einem Muster, das dem Ausdruck entspricht, wenn ich nur die Berichte, sagen wir, von einem Manager extrahieren wollte? Mit den anderen Lösungen wäre es: '| Manager ({Berichte = rep}) -> was auch immer'. – CSJ

+2

Ich habe v3.1 nicht installiert, aber laut der MSDN-Seite, die in meiner Antwort verlinkt ist, wäre es '| Manager (Berichte = rep) -> ... '. – Daniel

6

Mutually rekursive Typen sind mit type ... = ... and ... = ... erklärt:

type Employee = 
    | Engineer of Person 
    | Manager of Manager 
    | Executive of Executive 
and Manager = { Name: Person; Reports: Employee list } 
and Executive = { Name: Person; Reports: Employee list; Assistant: Employee} 
+0

Entschuldigung; Lee schlich es etwas schneller :) – CSJ