2012-10-19 15 views
5

ecco la mia domanda:Haskell: elenco degli elementi con restrizione di classe

questo funziona perfettamente:

type Asdf = [Integer] 
type ListOfAsdf = [Asdf] 

Ora voglio fare lo stesso, ma con l'integrale restrizione classe:

type Asdf2 a = (Integral a) => [a] 
type ListOfAsdf2 = (Integral a) => [Asdf2 a] 

Ho ricevuto questo errore:

Illegal polymorphic or qualified type: Asdf2 a 
Perhaps you intended to use -XImpredicativeTypes 
In the type synonym declaration for `ListOfAsdf2' 

Ho provato un sacco di cose ma non riesco ancora a creare un tipo con una restrizione di classe come descritto sopra.

Grazie in anticipo !!! =)

Dak

+0

Anche 'ListOfAsdf2' richiede un parametro di tipo. 'tipo ListOfAsdf2 a = Integrale a => [Asdf2 a]'. –

+0

Ho provato anche quello, ma ho ottenuto lo stesso errore .. = ( – dak

+0

Sì, hai bisogno di 'ImpredicativeTypes', come diceva il compilatore, ma in realtà, non hai bisogno del parametro type quindi. –

risposta

5

Ranting Contro gli Anti-Existentionallists

ho sempre piace il tipo di anti-esistenziale parlare in Haskell, come spesso trovo esistenziali utili. Per esempio, in alcuni test rapido controllo Ho codice simile a (codice non testato ironicamente segue):

data TestOp = forall a. Testable a => T String a 

tests :: [TestOp] 
tests = [T "propOne:" someProp1 
     ,T "propTwo:" someProp2 
     ] 

runTests = mapM runTest tests 
runTest (T s a) = putStr s >> quickCheck a 

E anche in un angolo di qualche codice di produzione che ho trovato a portata di mano per fare un elenco dei tipi che avevo bisogno valori casuali di:

type R a = Gen -> (a,Gen) 
data RGen = forall a. (Serialize a, Random a) => RGen (R a) 
list = [(b1, str1, random :: RGen (random :: R Type1)) 
     ,(b2, str2, random :: RGen (random :: R Type2)) 
     ] 

rispondere alla tua domanda

{-# LANGUAGE ExistentialQuantification #-} 
data SomeWrapper = forall a. Integral a => SW a 
5

Se avete bisogno di un contesto, il modo più semplice sarebbe quella di noi e una dichiarazione data:

data (Integral a) => IntegralData a = ID [a] 
type ListOfIntegralData a = [IntegralData a] 

*Main> :t [ ID [1234,1234]] 
[ID [1234,1234]] :: Integral a => [IntegralData a] 

Questo ha il (sola) effetto di rendere sicuro un Integral contesto viene aggiunto ad ogni funzione che utilizza il tipo di dati IntegralData.

sumID :: Integral a => IntegralData a -> a 
sumID (ID xs) = sum xs 

La ragione principale sinonimo type non funziona per voi è che tipo di sinonimi sono concepiti come solo che - qualcosa che sostituisce una tipo, non un tipo di firma .

Ma se si vuole andare esistenziale il modo migliore è con un GADT, perché gestisce tutti i problemi di quantificazione per voi:

{-# LANGUAGE GADTs #-} 

data IntegralGADT where 
    IG :: Integral a => [a] -> IntegralGADT 
type ListOfIG = [ IntegralGADT ] 

Poiché si tratta essenzialmente di tipo esistenziale, potete mescolarli in su:

*Main> :t [IG [1,1,1::Int], IG [234,234::Integer]] 
[IG [1,1,1::Int],IG [234,234::Integer]] :: [ IntegralGADT ] 

Che potresti trovare abbastanza comodo, a seconda dell'applicazione.

Il vantaggio principale di un GADT su una dichiarazione di dati è che quando si pattern match, è implicitamente ottiene il Integral contesto:

showPointZero :: IntegralGADT -> String 
showPointZero (IG xs) = show $ (map fromIntegral xs :: [Double]) 

*Main> showPointZero (IG [1,2,3]) 
"[1.0,2.0,3.0]" 

Ma la quantificazione esistenziale è talvolta usato per le ragioni sbagliate, (ad esempio, volendo per mescolare tutti i tuoi dati in una lista perché è quello che ti serve da da lingue digitate dinamicamente, e non ti sei abituato alla tipizzazione statica e ai suoi vantaggi ancora).

Qui credo che sia più problemi che ne vale la pena, a meno che non necessità di mescolare diversi tipi Integral insieme senza convertirli. Non vedo un motivo perché questo sarebbe d'aiuto, perché dovrai convertirli quando li usi.

Ad esempio, non è possibile definire

unIG (IG xs) = xs 

perché non ha nemmeno il tipo di controllo. Regola generale: non puoi fare cose che menzionano il tipo a sul lato destro.

Tuttavia, questo è OK perché abbiamo convertire il tipo di a:

unIG :: Num b => IntegralGADT -> [b] 
unIG (IG xs) = map fromIntegral xs 

quantificazione Qui esistenziale ha costretto a convertire i dati quando penso che il tuo piano originale era quello di non dover! Puoi convertire tutto in numero intero invece di questo.

Se vuoi le cose semplici, mantienile semplici. La dichiarazione dei dati è il modo più semplice per assicurarti di non inserire dati nel tuo tipo di dati, a meno che non sia già membro di una classe di tipi.

Problemi correlati