2008-11-20 7 views
21

Also, ich habe ein Paar Typklassen, die ich viel zusammen verwenden werde, und ich möchte vermeiden, beide jedes Mal zu spezifizieren. Grundsätzlich stattHaskell Typeclass Kurzschrift

:: (Ord a, Fractional a, Ord b, Fractional b, ... Ord z, Fractional z) => 

am Anfang aller meiner Art Spezifikationen setzen, ich eher so

:: (OrdFractional a, OrdFractional b, ... OrdFractional z) 

setzen würde, meine erste Idee, wie dies zu tun, war nur eine neue typeclass erklären

module Example where 

class (Fractional a, Ord a) => OrdFractional a 

example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool 
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3) 

Aber als automagically nicht funktioniert, wie ich wünschte, es wäre:

% ghci 
Prelude> :l Example.hs 
Ok, modules loaded: Example. 
Prelude Example> example (1::Float,3::Float) (2,2) (3,1) 

<interactive>:1:0: 
    No instance for (OrdFractional Float) 
     arising from a use of `example' at <interactive>:1:0-39 
    Possible fix: 
     add an instance declaration for (OrdFractional Float) 
    In the expression: example (1 :: Float, 3 :: Float) (2, 2) (3, 1) 
    In the definition of `it': 
     it = example (1 :: Float, 3 :: Float) (2, 2) (3, 1) 

manuell erstellen Instanzen scheint wie eine Drag so, als nächstes, ich dachte, ich könnte versuchen, automatisch Instanzen zu erstellen:

module Example where 

class OrdFractional a 
instance (Fractional a, Ord a) => OrdFractional a 

example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool 
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3) 

Aber der Compiler tat es nicht so:

ghc -c Example.hs 

Example.hs:4:0: 
    Illegal instance declaration for `OrdFractional a' 
     (All instance types must be of the form (T a1 ... an) 
     where a1 ... an are type *variables*, 
     and each type variable appears at most once in the instance head. 
     Use -XFlexibleInstances if you want to disable this.) 
    In the instance declaration for `OrdFractional a' 

So ist Kann ich das irgendwie machen?

Antwort

32

Mit der ConstraintKinds Erweiterung in GHC eingeführt 7.4, sind Einschränkungen jetzt Art von Art Constraint, so dass Sie gewöhnliche Art Synonyme verwenden können, bekommen, was Sie wollen:

{-# LANGUAGE ConstraintKinds #-} 

type OrdFractional a = (Ord a, Fractional a) 
10

Wenn der Compiler „Use -XFlexibleInstances“ sagt, sollten Sie versuchen,

{-# LANGUAGE FlexibleInstances #-} 

an der Spitze Ihrer Quelle hinzugefügt (und gehen Sie die Dokumentation lesen, was zu lernen, es tut natürlich!).

In diesem speziellen Fall, dies wird Ihren Code funktioniert:

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-} 

Flexible Instanzen sind erforderlich, um den => Kontext auf der Instanz Kopf und unentscheidbar Instanzen erforderlich sind, zu ermöglichen, da der Compiler, beim Umgang mit ein OrdFractional a Kontext, kann Ende hinzufügen Fractional a und Ord a zu dem Kontext - was nicht direkt hilft bei der endgültigen Bestimmung a, und unter angemessen schrecklichen Umständen kann Tippfehler abweichen; der Compiler mag das wirklich nicht. (Sie würden wahrscheinlich mögen es nicht, wenn der Compiler für immer ging oder lief aus der Erinnerung, auch nicht.)

3

Nr

Ihre Lösung einer übergeordneten Klasse die anderen Klassen impliziert ist in der Nähe zu dem, was Sie wollen, dass ist in Haskell möglich. Obwohl dies manuelle Instanzen dieser neuen Klasse erfordert, wird sie manchmal verwendet, beispielsweise in der rewriting-Bibliothek.

Wie CesarB erwähnte Klasse Aliase tun, was Sie wollen (und mehr), aber sie sind nur ein Vorschlag, der seit Jahren schon da ist und nie umgesetzt worden, wahrscheinlich, weil es zahlreiche Probleme damit gibt. Stattdessen sind verschiedene andere Vorschläge aufgetaucht, aber keine davon wurde auch implementiert. (Eine Liste dieser Vorschläge finden Sie unter Haskellwiki page.) Eines der Projekte unter Hac5 bestand darin, das GHC so zu modifizieren, dass es eine kleine Teilmenge von Klassenaliasen Kontextsynonyme enthält (die genau das tun, wonach Sie fragen, und nicht mehr)), aber leider wurde es nie beendet.

+3

Die neue ConstraintKinds Erweiterung sollte Kontext Synonyme ermöglichen. –