2016-07-29 24 views
0

Beachten Sie Folgendes:Get Constraint in GADT-Stil-Deklaration, ohne speziell Konstruktor zu verwenden?

{-# LANGUAGE GADTs, GADTSyntax #-} 

data Test a where 
    Test :: Ord a => { first :: a, second :: a } -> Test a 

comp :: Test a -> Bool 
comp (Test fst snd) = fst < snd 

Der Konstruktor Test ist mit einer Ord Einschränkung erklärt. In comp habe ich einen Parameter speziell genommen mit Test konstruiert, die die Ord Einschränkung gibt mir erlaubt nun <

zu verwenden, nehme ich schreiben wollte:

comp' :: Test a -> Bool 
comp' x = (first x) < (second x) 

Unter Verwendung der Projektionsfunktionen erhalten die erstes und zweites Element. Dies ist nicht okay, weil mein Parameter x nicht (unbedingt) mit Test konstruiert wurde, so gibt es keine Ord Einschränkung.

Also, für meine Frage, gibt es eine Möglichkeit, die Parameter zu nehmen, wie gerade x aber immer noch irgendwie die vom Test Konstruktor Ord Einschränkung hat, ohne „auspacken“ zu haben oder Mustererkennung auf das Test Konstruktor oder die Einschränkung hinzufügen zu meiner Funktion?

Was, warum ich das möchte, habe ich einen Datentyp mit einem Konstruktor viele Werte nehmen, von denen ich nur in dieser besonderen Funktion benötigen, so Auspacken macht es meine Funktion unnötig ausführliche:

myFunction :: Thing -> ... 
myFunction (Thing _ _ _ _ need _ _) ... 

im Gegensatz zu

myFunction t = ... (need t) 
+2

Sie könnten 'myFunction t @ Thing {} = ...' tun. – Alec

+0

'myfunction Thing {need = x}' Dies liefert das 'Ord'-Diktat und Sie haben auch den Wert des 'Need'-Feldes bereits in' x' entpackt. Es gibt auch eine Erweiterung, mit der Sie 'myFunction Thing {need}' schreiben können und im Body können Sie den Namen 'need' verwenden, um auf den Wert des' need' Feldes des Arguments zu verweisen. – Bakuriu

+0

Danke Jungs, wusste nicht über diese Syntax! – cemulate

Antwort

1

können Sie eine Funktion definieren, die alle, die aus dem Konstruktor extrahiert:

data Test a where 
    Test :: Ord a => { first :: a, second :: a } -> Test a 

openTest :: Test a -> (Ord a => r) -> r 
openTest Test{} x = x 

können Sie dann

comp :: Test a -> Bool 
comp x = openTest x $ first x < second x 

schreiben, aber beachten Sie, dass die Umsetzung von openTest ganz trivial ist - und es ist weniger tippt den Mustervergleich nur inline:

comp' :: Test a -> Bool 
comp' [email protected]{} = first x < second x 

Beachten Sie auch diese (d Die Test{}-Syntax) funktioniert mit jedem Konstruktor, auch wenn es kein Datensatzkonstruktor ist. Ihre eigentliche Funktion kann einfach als

myFunction [email protected]{} = ... (need t) ... 

oder äquivalent

openThing :: Thing a -> (ThingConstraints a => r) -> r 
openThing Thing{} x = x 

myFunction t = ... (openThing $ need t) ... 

Schließlich ausgedrückt werden, können Sie auch eine Funktion definieren ein bestimmtes Feld sowie die Einschränkungen zu extrahieren, die auf dieses Gebiet gelten, die sehr nützlich für große Konstruktoren mit vielen Einschränkungen sein:

first' :: Test a -> (Ord a => a -> r) -> r 
first' [email protected]{} x = x (first t)