2012-05-03 4 views
7

(scusate l'esempio terribilmente forzato)Come faccio a dare espressioni di tipi generici in una clausola "where"?

Quello che voglio fare è specificare i tipi in cui clausola:

somemap :: (a -> b) -> [a] -> [b] 
somemap f xs = ys 
    where 
    some = take 5 xs :: [a] 
    ys = map f some :: [b] 

Ma questo causa un errore:

*Main> :load file.hs 
[1 of 1] Compiling Main    (file.hs, interpreted) 

fil.hs:15:18: 
    Couldn't match expected type `a1' against inferred type `a' 
     `a1' is a rigid type variable bound by 
      an expression type signature at file.hs:15:25 
     `a' is a rigid type variable bound by 
      the type signature for `somemap' at file.hs:12:12 
     Expected type: [a1] 
     Inferred type: [a] 
    In the second argument of `take', namely `xs' 
    In the expression: take 5 xs :: [a] 

file.hs:16:13: 
    Couldn't match expected type `b1' against inferred type `b' 
     `b1' is a rigid type variable bound by 
      an expression type signature at file.hs:16:24 
     `b' is a rigid type variable bound by 
      the type signature for `somemap' at file.hs:12:17 
    In the first argument of `map', namely `f' 
    In the expression: map f some :: [b] 
    In the definition of `ys': ys = map f some :: [b] 
Failed, modules loaded: none. 

Considerando che devo specificare solo tipi di calcestruzzo, sostituendo Int per a e Bool per b, nessun problema:

somemap :: (Int -> Bool) -> [Int] -> [Bool] 
somemap f xs = ys 
    where 
    some = take 5 xs :: [Int] 
    ys = map f some :: [Bool] 

Quindi la mia domanda è: Come faccio a specificare i tipi generici e digitare i vincoli in un dove clausola?

risposta

15

All'interno della clausola di where, le variabili di tipo a e b sono nuove variabili tipo; le variabili di tipo non hanno scope, quindi ogni signature di tipo ha una nuova fornitura di esse, proprio come se fossero definite al livello più alto.

Se si accende l'estensione ScopedTypeVariables (mettere {-# LANGUAGE ScopedTypeVariables #-} nella parte superiore del file), e cambiare dichiarazione di tipo somemap s' a:

somemap :: forall a b. (a -> b) -> [a] -> [b] 

allora le definizioni clausola where specificati funziona correttamente. Penso che gli forall s siano richiesti solo per la compatibilità con le versioni precedenti, quindi il codice che riutilizza le variabili di tipo nelle clausole where per i valori polimorfici non si interrompe.

Se non si desidera utilizzare un'estensione, l'alternativa consiste nel definire le brutte funzioni di supporto per unificare i tipi, ad esempio asTypeOf.

+1

Il codice in http://stackoverflow.com/questions/7408911/haskell-magical-code-whats-going-on-here è un buon esempio della confusione che può derivare da tali "brutte funzioni di supporto". –

Problemi correlati