Eigentlich ist es möglich, es gibt einen Weg, dies zu tun:
type [<Measure>] seconds
type [<Measure>] minutes
type [<Measure>] hours
let seconds_per_minute = 60<seconds>/1<minutes>
let minutes_per_hour = 60<minutes>/1<hours>
let minutes_to_seconds minutes seconds = minutes * seconds_per_minute + seconds
let hours_to_minutes hours minutes = hours * minutes_per_hour + minutes
type D1 = D1
type D2 = D2
type Sum = Sum with
static member inline ($) (Sum, _:^t when ^t: null and ^t: struct) = id
static member inline ($) (Sum, b) = fun _ _ a -> a + b
static member ($) (Sum, b:int<minutes>) = fun D1 _ a -> hours_to_minutes a b
static member ($) (Sum, b:int<seconds>) = fun D1 D2 a -> minutes_to_seconds a b
let inline (+) a b :'t = (Sum $ b) D1 D2 a
let duration = 1<hours> + 2<minutes> + 3<seconds>
Aber es ist wirklich Hacky, ich würde es nicht empfehlen.
UPDATE
Basierend auf den hier Kommentare sind einige Antworten:
Diese Technik verwendet Überlastungen, die zum Zeitpunkt der Kompilierung aufgelöst werden, so dass es während der Laufzeit keine Leistungseinbuße. Es basiert auf dem, was ich vor einiger Zeit in my blog geschrieben habe.
Um weitere Überlastungen fügen Sie mehr Dummy-Parameter hinzugefügt werden (D3
, D4
, ...) und schließlich, wenn Sie einige Überlastungen hinzufügen entscheiden, die mit einer bestehenden Konflikt Sie einen ternären Operator verwenden, müssen möglicherweise (?<-)
oder ein Funktionsaufruf mit expliziten statischen Member-Constraints. Here's a sample code.
Ich denke, ich würde es nicht verwenden, da es viele Hacks (eine Dummy-Überladung und 2 Dummy-Typen) erfordert und der Code weniger lesbar wird. Wenn F # schließlich mehr Unterstützung für Inline-Funktionen auf der Basis von Überladungen bietet, würde ich es definitiv in Betracht ziehen.
Phil Trelford's technique (in Reeds Antwort erwähnt) funktioniert zur Laufzeit, eine dritte Option wäre, Phantom-Typen zu verwenden, kann es weniger Hacks erfordern.
Fazit
Wenn ich zwischen allen Alternativen zu wählen hätte, würde ich diese Technik verwenden, aber noch deutlicher an der Aufrufstelle zu sein, ich meine, ich würde Konvertierungsfunktionen wie minutes
, seconds
und diese Weise definieren an der Aufrufstelle würde ich schreiben:
let duration = seconds 1<hours> + seconds 2<minutes> + 3<seconds>
Und dann diese Konvertierungsfunktionen zu definieren wir Überlastungen verwenden würden, aber es wäre weniger hacky als Neudefinition einen exis Binärer Operator.
Wow, das ist großartig! Ich habe jedoch ein paar Fragen: 1. Warum empfiehlst du es nicht? 2. Verliere ich die Typensicherheit? 3. Wenn du wählen müsstest, würdest du lieber mit Phil Trelforts Laufzeitlösung gehen oder das? 4. Was macht $ eigentlich? Danke! – user3323923
Btw, ich wünschte, ich könnte zwei Antworten akzeptieren. – user3323923
@ user3323923, Gustavo definiert einen Operator '$' mit Klammern '($)'. @Gustavo, ich zweitens die Frage, warum würdest du es nicht benutzen? Es scheint eine legitime Lösung zu sein. –