2016-05-03 3 views
1

Gibt es eine Haskell-Sprachenerweiterung für die Typklassenmethode "die einzige mögliche verfügbare Instanz zu verwenden"?Wählen Sie die Standardinstanz unter mehrdeutigen Typen

Ich möchte folgendes

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FlexibleInstances  #-} 

class Foo a r where 
foo :: a -> r 


instance Foo a (Bool -> a) where 
    foo x _ = x 

-- This compiles 
-- bar :: Int -> Bool 

-- This does not 
bar :: a -> Bool 
bar _ = True 


use :: Bool 
use = bar $ foo _5 True 
    where 
    _5 :: Int 
    _5 = 5 

Jetzt kompilieren bekomme ich die folgende Fehlermeldung:

 No instance for (Foo Int (Bool -> r0)) 
    (maybe you haven't applied enough arguments to a function?) 
    arising from a use of ‘foo’ 
The type variable ‘r0’ is ambiguous 
Note: there is a potential instance available: 
    instance Foo a (Bool -> a) -- Defined at tests/pos/Fixme.hs:9:10 

Aber da gibt es nur eine mögliche Instanz verfügbar ist, ist es eine Möglichkeit, ghc zu zwingen, zu verwenden, diese Instanz? Oder gibt es eine Möglichkeit, eine Instanz als eine Standardinstanz zu deklarieren, wenn Typen nicht eindeutig sind?

+3

Diese typeclass + -Instanz lässt mich zusammenzucken. Sind Sie sicher, dass Sie hier das Richtige sagen? –

Antwort

3

Der Standard Trick ist die Instanz mehr polymorphe zu machen, also:

instance (a ~ b, bool ~ Bool) => Foo a (bool -> b) where 
    foo x _ = x 

Dies schließt Sie aus anderer Funktion Instanzen zu schreiben, macht aber klar, welche Arten zu verwenden, wenn eine Funktionsinstanz gesucht. Sie müssen dazu die Erweiterung TypeFamilies aktivieren. In Ihrem speziellen Fall können Sie nur mit instance a ~ b => Foo a (Bool -> b) durchkommen, was weitere Funktionsinstanzen mit anderen Argumenttypen auf Kosten von häufigeren Mehrdeutigkeitsfehlern zulassen würde.

Weitere Erläuterungen zu diesem Trick finden Sie unter a previous answer of mine.

+0

Danke Daniel! Ich kann den 'Bool' so lassen wie er ist! Folgendes ist genug! 'Beispiel (a ~ b) => Foo a (Bool -> b) wo foo x _ = x' – Niki

+0

Ich versuche zu verstehen, warum dieser Trick funktioniert: Ist es, dass die Instanz so allgemein ist, zuerst die Instanz wird vom Typprüfer "akzeptiert" und _dann wird die Einschränkung "a ~ b" überprüft? In meinem ersten Beispiel, was verhindert, dass "r" zu "Int" instanziiert wird. – Niki

+0

@Niki Korrekt: Instanzkontexte (Dinge links von '=>') werden ignoriert, wenn eine Instanz ausgewählt wird. In Ihrem Beispiel verhindert nichts, dass "r" zu "Int" instanziiert wird - aber auch nichts zwingt es; da jemand möglicherweise später mitkommen und eine Instanz für z.B. 'instance Foo Int (Bool ->())', ist es nicht klar, dass die vorhandene Instanz die richtige zu wählen ist. Auch wenn es die einzige Übereinstimmung ist, wenn die aktuellen Module kompiliert werden, bedeutet die Open-World-Annahme, dass später weitere Kompilierungseinheiten hinzugefügt werden können. –

Verwandte Themen