2016-12-12 3 views
2

kann ich einen Zitat Ausdruck Parameter definieren, so dass nicht nur der resultierende Typ des Ausdrucks ist kompiliert Zeit sondern auch die Call-Site-Ausdruck.Check Code Quotation Struktur während der Kompilierung

lässt ein Beispiel sehen:

type A = { 
    a : int 
} 

type Checker() = 
    static member Check(e : Expr<int>) : ResultType = ... 

Die folgenden offensichtlich

let a = { a = 1 } 
Checker.Check <@ a.a @> 

Resultierende in einem tatsächlichen Ausdruck ähnlich PropertyGet(..., PropertyGet (....), a) der Eingabe überprüfen.

Und nun eine andere Art und Weise

let getInt (a:A) : int = a.a 

Nachfolgend stellt auch

Checker.Check <@ getInt a @> 

Doch wie kann ich verhindern, dass zweites Beispiel kompiliert und nur für PropertyGet s erlauben? (nur als ein Beispiel).
Ich weiß, ich kann die Struktur des Ausdrucks zur Laufzeit überprüfen - aber ich möchte eine Kompilierzeit überprüfen.

+5

Sie können nicht. Wenn dies eine kritische Anforderung ist, schlage ich vor, anstelle von Zitaten eine Bibliothek von Kombinatoren zu verwenden. –

+0

Wie würde das helfen? – robkuz

+1

Sie können bewirken, dass Ihre Kombinatoren (oder besser gesagt, der Datentyp, den sie erzeugen) keine ungültigen Daten erstellen können. Sie wissen, "machen ungültige Daten nicht darstellbar" und all das. –

Antwort

1

Wie Fjodor in einem Kommentar gesagt hat, gibt es keine Möglichkeit sicherzustellen, dass Zitate zur Kompilierungszeit nur eine bestimmte Form haben. Das ist sehr bedauerlich, aber alle zitatbasierten (oder ausdrucksbaumbasierten) Bibliotheken leiden darunter (vor allem LINQ) und wenn Ihre Anforderung "nur Eigenschaften-Getters" ist, dann nehme ich an, dass Sie dies wahrscheinlich als eine Laufzeitprüfung belassen können .

Wenn ich das wirklich garantieren wollte, würde ich wahrscheinlich versuchen, die F# Compiler Service zu verwenden, die Sie typed expression tree erhalten können. Sie könnten dann über den Baum gehen und alle Zitate im Projekt finden und die Fehler melden (es könnte in erweiterbarer Weise als ein Linter-Plugin ausgeführt werden, von dem auch andere profitieren könnten).

Wenn Sie in der DSL Richtung ging, schreiben Sie könnten dann sagen, a |> get "foo" |> get "bar" (mit Rohr) oder a?foo?bar (mit dem ? Operator), aber dann auf den Namen, die Sie verlieren Kontrolle, die als nicht schlechter zu sein scheint in der Lage sein, die korrekte Form eines Angebots zu überprüfen.

+0

Die untypisierte Variante ist definitiv kein Weg zu gehen ;-) Ich bin mir aber nicht sicher, wie die Compiler-Dienste und der typisierte Ausdrucksbaum helfen würden. Zumindest, wenn wir im Rahmen des normalen Arbeitsablaufs und nicht einer 2-Pass-Kompilation sprechen. Können Sie vielleicht skizzieren, wie Sie sich das vorstellen? – robkuz

+0

@robkuz Du brauchst definitiv so etwas wie eine Zwei-Pass-Compilation. Aber Sie könnten dies als eine Integration in FSharpLint (https://github.com/fsprojects/FSharpLint) tun und es als VS-Plugin, die die Erfahrung schöner machen würde. –

Verwandte Themen