Frage

Nehmen wir an, ich habe ein F# -Modul zum Umgang mit dreidimensionalen Vektoren und der Messeinheit definiert:

[<Measure>]
type m
[<Measure>]
type s
[<Measure>]
type v = m/s
[<Measure>]
type rad

type Vector3<[<Measure>] 'a> =
    {
    X : float<'a>
    Y : float<'a>
    Z : float<'a>
    }

Und irgendwo habe ich einen Winkel in Radians:

let angle:float32<rad> = 0.5f<rad>

Jetzt muss ich einen Vektor3 (Geschwindigkeit) unter Verwendung des Winkels deklarieren, um seine Komponenten zu berechnen. Ich habe so etwas ausprobiert:

let velocity : Vector3<m/s> = { X = Math.Cos(angle);Y = Math.Sin(angle);Z = 0.0<m/s>} //don't compile

Der obige Code ist nicht kompiliert, da Vector3 einen Wert in x und y erwartet, aber SIN gibt einen Schwimmer zurück.

Wie kann ich dieses Problem lösen? Wenn es möglich ist, möchte ich eine Konvertierung zwischen Messeinheiten anstelle einer Besetzung durchführen, so dass der Compiler garantieren kann, dass ich das Richtige mache und gleichzeitig einen Winkel in eine Geschwindigkeit verwandle.

Irgendein Vorschlag?

War es hilfreich?

Lösung

Mehrere Probleme hier:cos erwartet einen unitlosen Wert, also müssen Sie die Einheiten ausziehen angle; Angesichts der Tatsache, dass die Geschwindigkeit erwartet float und nicht float32, Sie könnten genauso gut direkt konvertieren float (was die Einheiten entfernt).

Dann müssen Sie die Einheiten wieder einsetzen. In den ersten Versionen von Maßeinheiten können Sie dies tun, indem Sie einfach in der entsprechenden Maßnahme mit 1 multiplizieren. Jetzt gibt es da LanguagePrimitives.FloatWithMeasure, was korrekter, aber etwas ausführlicher ist.

let velocity =
 {
     X = angle |> float |> cos |> LanguagePrimitives.FloatWithMeasure<m/s> ;
     Y = angle |> float |> sin |> LanguagePrimitives.FloatWithMeasure<m/s> ;
     Z = 0.0<m/s> ;
 }

Abgesehen von 10 Radians ist ein lustiger Winkel ...

(Beachten Sie, dass cos und sin sind eingebaut)

Andere Tipps

OK, hier ist eine weitere Einstellung, die demonstriert, wie Sie eine Skalargeschwindigkeit und eine 2D-Richtung kombinieren können, um Ihre Einheiten wirklich zu nutzen:

let vvector (velocity:float<'u>) (xydirection:float<rad>) =
    { 
        X = cos (float xydirection) * velocity;
        Y = sin (float xydirection) * velocity;
        Z = 0.<_>
    }

Was gibt:

> vvector 15.3<m/s> angle<rad>;;
val it : Vector3<m/s> = {X = 13.4270132;
                         Y = 7.335210741;
                         Z = 0.0;}

Sie können einen Schritt weiter gehen, indem Sie einen Operator zu Ihrem Vector3 -Typ hinzufügen:

static member (*) (v1: Vector3<'u>, n: float<'v>) =
    { X = v1.X * n; Y = v1.Y * n; Z = v1.Z * n }

Das würde bedeuten, dass Sie das dann tun könnten:

let vvector2 (velocity:float<'u>) (xydirection:float<rad>) =
    { X = cos(float xydirection); Y = sin(float xydirection); Z = 0. } * velocity

Offensichtlich "benutzt" Sie Ihre Radianer immer noch nicht wirklich, aber das ist erwartet, Radians sind sowieso irgendwie "Nicht" -Anheiten. Eine Möglichkeit, wie Sie könnte Nutzen Sie sie, wenn Sie Radiants verwalten möchten und Grad. Sie können zwei weitere statische Mitglieder zu Ihrem Vektor3 hinzufügen:

static member ofAngle (ang:float<rad>) = 
    { X = cos(float ang); Y = sin(float ang); Z = 0.0 }
static member ofAngle (ang:float<degree>) = 
    Vector3<'u>.ofAngle(ang * 2.<rad> * System.Math.PI / 360.<degree>)

Das sieht gut aus, aber leider wird es nicht kompilieren, weil The method 'ofAngle' has the same name and signature as another method in this type once tuples, functions and/or units of measure are erased. Sie können auschecken diese Frage für mehr Details

Wenn es möglich ist, möchte ich eine Konvertierung zwischen Messeinheiten anstelle einer Besetzung durchführen, so dass der Compiler garantieren kann, dass ich das Richtige mache und gleichzeitig einen Winkel in eine Geschwindigkeit verwandle.

Sie bitten um widersprüchliche Dinge. Messeinheit hilft, die Korrektheit von Programmen zu gewährleisten, indem die Typinferenz verwendet wird, um Einheiten in den Programmen durchzusetzen, sodass die Konvertierung explizit durchgeführt werden muss.

Wie @Benjol sagte, müssen Sie zwischen dimensionalen und dimensionslosen Daten konvertieren. Unter dem Code befindet sich eine informelle Version, in der ich mich konvertiere float zu float<m/s> Durch Multiplizieren mit seinem Einheitswert:

let angle:float32<rad> = 0.5f<rad>

let velocity = {
                X = sin (float angle) * 1.0<m/s> ; 
                Y = cos (float angle) * 1.0<_> ; 
                Z = 0.0<_>
               } 

Beachten Sie, dass Sie nur eine Einheit für x angeben müssen. Andere Einheiten werden basierend auf der Typ -Deklaration von abgeleitet Vector3.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top