2017-12-18 7 views
9

Zum Beispiel habe ich eine Art Klasse:Ist es in Haskell möglich, eine Standardimplementierung für eine partiell angewendete Klasse mit mehreren Parametern bereitzustellen?

class MyClass a b c where 
    fun01 :: a -> b 
    fun02 :: a -> c 

    fun03 :: a -> b -> c ->() 
    fun04 :: a -> WhatEver 

ich für meine eine Standardimplementierung bieten möchten, lassen Sie uns es BaseDataType nennen, die Implementierungen von fun03 in Bezug auf sie selbst und fun01 und fun02 definiert. Dann würde ich so etwas wie dieses:

class MyClass BaseDataType b c where 
    fun03 = fun01 <$> fun02 ... 
    fun04 = fun02 ... 

Und als meine Klasseninstanz abzuschließen und vermeiden alle Standardcode für fun03 und fun04 ich nur fun01 und fun02 wie diese bieten würde:

instance MyClass BaseDataType Int Char where 
    fun01 = 1 
    fun02 = 'C' 

Gibt es möglicherweise eine Spracherweiterung, die diese Art von Verhalten ermöglicht? Zu diesem Thema konnte ich nichts finden.

Antwort

10

Es gibt keine solche Erweiterung, aber Sie können diese Funktionalität erreichen einfach durch Ihre Klasse in zwei Klassen aufgeteilt:

class MyClass1 a b c where 
    fun03 :: a -> b -> c ->() 
    fun04 :: a -> WhatEver 

class MyClass1 a b c => MyClass2 a b c where  
    fun01 :: a -> b 
    fun02 :: a -> c 

Dann arbeiten Sie Instanzen, wie Sie wollen:

-- NB: need the MyClass2 constraint if you use `fun01` or `fun02` in the definitions 
-- This requires UndecidableInstances 
instance MyClass2 BaseDataType b c => MyClass1 BaseDataType b c where 
    fun03 = fun01 <$> fun02 ... 
    fun04 = fun02 ... 

instance MyClass2 BaseDataType Int Char where 
    fun01 = 1 
    fun02 = 'C' 

Benutzer deiner Klasse sind nicht betroffen; Sie können weiterhin konsumieren MyClass2, wo sie vorher MyClass verwendet und erhalten genau die gleiche Funktionalität.


Abgesehen: die ursprüngliche Definition von MyClass und MyClass1 und MyClass2 nicht einmal durch mehrere mehrdeutige Art Fehler kompiliert (c ist nicht in der Art des fun01 erwähnt, etc.) - Ich gehe davon aus dieser Klasse war nur zu Demonstrationszwecken definiert und ich habe nicht versucht, dies zu beheben.

4

Sie können DefaultSignatures verwenden wie dieses

class MyClass a b c where 
    fun01 :: a -> b 
    fun02 :: a -> c 

    fun03 :: a -> b -> c ->() 
    default fun03 :: (a ~ BaseDataType) => a -> b -> c ->() 
    fun03 = fun01 <$> fun02 ... 

    fun04 :: a -> WhatEver 
    default fun04 :: (a ~ BaseDataType) => a -> WhatEver 
    fun04 = fun02 ... 
+2

+1, aber ich weiß nicht zu rechnen dies für die OP usuable ist, da der Standard _for ist all_ 'MyClass' Instanzen, nicht nur für die' MyClass BaseDataType' Spezialisierung. (In anderen Fällen führt die Standardimplementierung nur zu einem obskuren Fehler, der angibt, dass eine benutzerdefinierte Instanz ersetzt werden muss.) – leftaroundabout

Verwandte Themen