2013-03-05 24 views
6

Ho una classe chiamata Foo che possiede una funzione gen :: Int -> [Foo]. Per esempio, ho potuto fare un esempio di Foo in questo modo:Creare una classe un'istanza di un'altra classe

data FooTest = FooTest Int 

instance Foo FooTest where 
    gen n = replicate n (FooTest 0) 

Ora, proviamo ad immaginare Ho un'altra classe chiamata Bar che definisce una funzione bar :: Bar -> IO(). Ogni istanza di Foo deve essere un'istanza di Bar, ma l'implementazione di Bar è praticamente la stessa per ogni istanza. Ecco un esempio:

class Foo f where 
    gen :: Int -> [f] 

class Bar b where 
    bar :: b -> IO() 

instance Bar Foo where -- obviously that doesn’t work 
    bar _ = putStrLn "bar through any Foo instance" 

instance (Foo f) => Bar f where -- this needs the FlexibleInstance GHC extension first, then it still throws shit saying that the constraint is not smaller that I don’t shit 
    bar _ = putStrLn "bar through any Foo instance" 

Il problema qui è che non riesco a trovare nessuna modi per fare una classe un'istanza di un altro parlare del fatto che qualsiasi istanza della prima classe condividerà la stessa implementazione per instancing l'altro classe.

Qualche idea?

Grazie in anticipo.

risposta

4

È possibile eseguire esattamente ciò che si desidera utilizzando l'ultima istanza con due estensioni: FlexibleInstances e UndecidableInstances.

Proprio come suggerisce il nome, la seconda estensione consente di scrivere potenzialmente le istanze che non terminano. Ciò potrebbe portare ad un ciclo infinito in fase di compilazione; tuttavia, l'implementazione è arbitrariamente limitata a una determinata profondità di ricorsione, quindi non dovresti avere tempi di compilazione infiniti.

Non conosco alcun modo per farlo senza alcuna estensione. Tuttavia, l'utilizzo delle estensioni non è intrinsecamente dannoso a meno che non si desideri utilizzare altri compilatori in futuro.

Inoltre, una nota di stile casuale: le parentesi sono facoltative se si dispone di un solo vincolo. Quindi potresti scriverlo come:

instance Foo f => Bar f where ... 

Questo non è molto importante, ma penso che la seconda versione sia migliore.

+0

grazie mille! Per mia conoscenza, a cosa serve 'FlexibleInstance'? Le due estensioni funzionano in coppia? – phaazon

+1

Scrivo coerentemente le parentesi in tutti i contesti. Ciò rende più leggibili le firme dei tipi e le intestazioni di classe/istanza. Quindi non sono d'accordo con la tua nota di stile. – ertes

+0

Riguardo a FlexibleInstaces: vedere anche questo QA: http://stackoverflow.com/questions/8367423/are-haskell-flexibleinstances-a-stable-extension-to-the-language – scravy

Problemi correlati