Begrenzen Sie eine Zahl auf einen Bereich (Haskell)

7

Ich stelle eine Funktion zur Verfügung, die zwei Parameter benötigt, eine ist eine Mindestgrenze und die andere ist eine Höchstgrenze. Wie kann ich mit Typen sicherstellen, dass beispielsweise die Mindestgrenze nicht größer ist als die Maximalgrenze?

Ich möchte es vermeiden, einen intelligenten Konstruktor zu erstellen und ein Maybe zurückzugeben, da dies die gesamte Verwendung umständlicher machen würde.

Danke

    
doodledood 01.10.2016, 18:44
quelle

4 Antworten

12

Dies beantwortet Ihre Frage nicht genau, aber ein Ansatz, der manchmal funktioniert, ist, Ihre Interpretation Ihres Typs zu ändern. Zum Beispiel statt

%Vor%

könnten Sie

verwenden %Vor%

Auf diese Weise kann kein ungültiger Bereich dargestellt werden.

    
dfeuer 01.10.2016, 21:55
quelle
9

Diese Lösung verwendet abhängige Typen (und könnte zu schwergewichtig sein, überprüfen Sie, ob die Antwort von dfeuer für Ihre Bedürfnisse ausreicht).

Die Lösung verwendet das GHC.TypeLits -Modul von base sowie die typelits-Zeugen Paket.

Hier ist eine Differenzfunktion, die zwei ganzzahlige Argumente (statisch bekannt) annimmt und sich bei der Kompilierung beschwert, wenn die erste Zahl größer als die zweite ist:

%Vor%

Wir können es von GHCi überprüfen:

%Vor%

Aber was, wenn wir die Funktion mit zur Laufzeit bestimmten Werten verwenden wollen? Sprich, Werte, die wir aus der Konsole oder aus einer Datei lesen?

%Vor%

In diesem Fall verwenden wir Funktionen wie someNatVal und isLE . Diese Funktionen können mit Nothing fehlschlagen. Gelingt dies jedoch, geben sie einen Wert zurück, der eine Einschränkung "bezeugt". Und durch Mustervergleich auf dem Zeugen bringen wir diese Einschränkung in den Geltungsbereich (dies funktioniert, weil der Zeuge eine GADT ist).

In diesem Beispiel bringt die Just (SomeNat proxyn,SomeNat proxym) -Musterübereinstimmung KnownNat für die beiden Argumente in den Gültigkeitsbereich. Und die Just Refl Musterübereinstimmung bringt die n <= m Einschränkung in den Gültigkeitsbereich. Nur dann können wir unsere Funktion difference aufrufen.

Also haben wir in gewisser Weise die ganze Arbeit verschoben, um sicherzustellen, dass die Argumente die erforderlichen Voraussetzungen aus der Funktion selbst erfüllen.

    
danidiaz 01.10.2016 22:52
quelle
1

Was Sie verlangen, sind abhängige Typen. Es gibt ein nettes Tutorial dazu in Ссылка

Obwohl ich nicht weiß, wie freundlich es sein wird. Beachten Sie, dass die abhängige Typisierung in GHC 8.0 verbessert wurde, aber ich habe keine Erfahrung in diesem Bereich. Ich würde sicherstellen, dass Sie mit der Vorlage Haskell vertraut sind, wenn Sie nicht wollen, dass es umständlich ist.

    
EvHi 01.10.2016 21:44
quelle
1

Sie müssen den Maybe -Typ nicht aufrufen, um "intelligente Konstruktoren" zu nutzen. Wenn Sie möchten, können Sie Konstruktoren der Form (min,max) oder (max,min) akzeptieren und trotzdem einen data type erzeugen, der richtig interpretiert, welcher welcher ist.

Zum Beispiel könnten Sie ein kleines Modul machen:

%Vor%

Und jetzt, wenn Sie ein Range mit makeRange erstellen, wird das 2-Tupel automatisch so arrangiert, dass es in der Form (min,max) ist. Beachten Sie, dass der Konstruktor für Range nicht exportiert wird. Daher kann der Benutzer des Moduls keine ungültige Range erstellen. Sie müssen lediglich sicherstellen, dass Sie gültige Module in diesem Modul erstellen.

    
Myridium 02.10.2016 06:34
quelle