2015-06-02 3 views
13

Ho un problema relativo al sistema di tipo Haskell. Questa non è la prima volta che ho riscontrato i limiti del sistema di tipi. Ometterò i dettagli del mio progetto e utilizzerò un esempio semplificato. Ecco il codice:Haskell: le variabili di tipo possono essere utilizzate all'interno della definizione della funzione?

-- Works 
foo :: (Bounded a, Enum a) => a 
foo = minBound 

-- "ambiguous" constraint: 
-- 'a' has no occurrences in type declaration 
bar :: (Bounded a, Enum a) => Int 
bar = fromEnum minBound 

-- Too much information in return 
-- but I can show haskell the appropriate type of 'min' 
baz :: (Bounded a, Enum a) => (a, Int) 
baz = let min = minBound 
    in (min, someFunction . fromEnum $ min) 

-- Type constraint 'a' not ambiguous 
--  (or at least that isn't the compiler error message) 
-- but Haskell doesn't know which 'minBound' to use 
barrer :: (Bounded a, Enum a) => a 
barrer = let min = minBound -- <- min's type is ambiguous 
    in toEnum . someFunction . fromEnum $ min 

Quello che sto cercando di realizzare è simile a barrer: In primo luogo, utilizzare il valore minBound specifiche per il tipo a e 'cast' in un numero intero. Nel mio progetto, procedo a trasformare questo numero intero (per evitare gli overflow aritmetici intermedi quando si utilizza il tipo a) e "lanciarli" per digitare a (dopo un po 'di magia mod). Come posso dire ad Haskell il tipo appropriato di minBound? È possibile?

La soluzione ovvia è aggiungere un'annotazione di minBound :: a. Questo avrebbe anche risolto bar. Il problema: la variabile di tipo a sembra essere fuori ambito nella definizione della funzione, poiché Haskell rinfresca minBound :: a in minBound a0 nel messaggio di errore. C'è un modo per fare questo tipo di annotazione?

Una cattiva modifica che ho usato era di limitare il tipo della chiamata minBound includendola nel tipo di ritorno della funzione, a la baz. Questa soluzione non è l'ideale. Qualcuno ha qualche consiglio?

risposta

14

L'estensione ScopedTypeVariables risolve esattamente il problema. La pagina fornisce anche alcune soluzioni alternative (argomenti asTypeOf e undefined).

+0

"Variabili di tipo scoped" - Esattamente quello che volevo. E detto molto più succintamente del mio titolo! – bimmo

+0

Come lo faresti anche con asTypeOf e undefined? Mi sembra che non si possa mai ottenere un valore di tipo 'a' da puntare a TypeTypeOf, perché nessuno viene passato o restituito da questa funzione. Si può ottenere solo uno tramite variabili di tipo scoped, a quel punto non è più necessario asTypeOf o undefined. – amalloy

+2

@amalloy Poiché 'asTypeOf' non valuta mai il suo secondo argomento, lo usa solo per l'inferenza di tipo, puoi legarlo in nodi come questo:' 'barrer = let min = minBound' asTypeOf' result; risultato = toEnum. qualche funzione. daEnum $ min in result'' –