2016-04-02 6 views
3

Gibt es eine Möglichkeit, leere Beschränkungen mit GHC < 7.8.1 zu simulieren? Etwas ähnlich wieGibt es eine Möglichkeit, leere Beschränkungen mit GHC <7.8.1 syntaktisch zu simulieren?

{-# LANGUAGE NullaryTypeClasses #-} 
class HasCallStack 
instance HasCallStack 

so dass z.B.

foo :: HasCallStack => Int -> Int 

als

foo :: Int -> Int 

Motivation

GHC 8.0.1 stellt HasCallStack als technisch das gleiche ist:

HasCallStack = (?callStack :: CallStack) 

Für eine Kompatibilität Shim I HasCallStack für alle definieren möchten Versionen von GHC zurück zu 7.0.1.

Für Versionen von GHC, die Unterstützung für implizit auf Parametern basierende Aufruf-Stacks haben, sollte HasCallStack funktionell dem entsprechen, was wir in GHC 8.0.1 haben.

Für Versionen von GHC, die Unterstützung für implizite Parameter basierend Anruf fehlen stapelt (dh alle Versionen von GHC < 7.10.2), HasCallStack sollte funktionell äquivalent zu dem leeren constraint sein.

Für Vollständigkeit, hier ist der Code, die wir verwenden könnten, wenn wir nur über GHC Pflege 7.8.1 und später:

#if MIN_VERSION_base(4,8,1) 
type HasCallStack = (?callStack :: CallStack) 
#else 
class HasCallStack 
instance HasCallStack 
#endif 

Gibt es eine Möglichkeit, diese Arbeit für ältere Versionen von GHC zu machen?

Als Referenz, ich werde meine aktuelle Lösung als Antwort hinzufügen. Aber ich würde gerne Eingabe auf andere Möglichkeiten, um dies zu bewältigen.

+0

Ich habe keine Ghc-Version älter als 7.10 - funktioniert 'Typ HasCallStack = (() :: Constraint)? Sie benötigen '-XConstraintKinds' und' importieren GHC.Exts (Constraint) ' – user2407038

+0

' Typ HasCallStack = (() :: Constraint) 'funktioniert für GHC-Versionen zurück zu GHC 7.4.1. Das ist schön! –

+0

Sie könnten auch '#define HasCallStack()' verwenden - dies würde 'ConstraintKinds' vermeiden und würde mehr Versionen von ghc unterstützen. '()' ist eine gültige Einschränkung sogar in Haskell 98. – user2407038

Antwort

4

Ich kenne keine Möglichkeit, genau die gleiche Syntax wie in GHC 8.0.1 zu unterstützen. Es ist jedoch möglich, optional eine Einschränkung hinzuzufügen, indem Sie den Typ Synonym und Rank2Types verwenden. Der folgende Code funktioniert für alle Versionen von GHC zurück zu 7.0.1.

#if MIN_VERSION_base(4,8,1) 
type HasCallStack a = (?callStack :: CallStack) => a 
#else 
type HasCallStack a = a 
#endif 

Das Beispiel aus Ihrer Frage

foo :: HasCallStack => Int -> Int 

wird

foo :: HasCallStack(Int -> Int) 

Beachten Sie, dass diese recht robust ist. Ich bin keiner Situation begegnet, in der dies nicht funktionieren würde, z. funktioniert auch, wenn foo andere Einschränkungen hat oder wenn foo eine class Methode ist.

+0

'RankNTypes' sollte nur für die (effektive) Verwendung von' HasCallStack' auf der linken Seite eines Pfeils benötigt werden, richtig? – dfeuer

+0

Von dem, was ich versucht habe, benötigen Sie 'Rank2Types' /' RankNTypes' zum Definieren von 'HasCallStack'. In Modulen, die nur 'HasCallStack' verwenden, benötigen Sie nur' FlexibleContexts'. –