2012-04-10 10 views
11

ero tanto sonno che ho scritto il seguente codice (modificato per mostrare solo la confusione):Haskell: Perché non vi è alcuna mancata corrispondenza di tipo (e perché viene compilata)?

fac s = take 10 [s, s `mod` 1 ..] 

maxFactor x = if (s == []) 
       then x 
       else head <-- this should be 'head x' instead of just 'head' 
    where s = fac x 

Tuttavia, questo carico in ghci (e compila) bene. Quando ho eseguito maxFactor 1, si lamenta (ovviamente):

<interactive>:0:1: 
    No instance for (Integral ([a0] -> a0)) 
     arising from a use of `maxFactor' 
    Possible fix: 
     add an instance declaration for (Integral ([a0] -> a0)) 
    In the expression: maxFactor 1 
    In an equation for `it': it = maxFactor 1 

<interactive>:0:11: 
    No instance for (Num ([a0] -> a0)) 
     arising from the literal `1' 
    Possible fix: add an instance declaration for (Num ([a0] -> a0)) 
    In the first argument of `maxFactor', namely `1' 
    In the expression: maxFactor 1 
    In an equation for `it': it = maxFactor 1 

Tuttavia, non capisco questo comportamento:

fac 's tipo è:

fac :: Integral a => a -> [a] 

mentre maxFactor' s tipo è:

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a 

Questo non significa e seguente:

  1. il primo ingresso fac deve essere di typeclass Integral (ad esempio, fac 10);
  2. in quanto nella definizione di maxFactor, c'è fac x, x deve essere anche di typeclass Integral, in tal modo, il tipo maxFactor s' sarebbe cominciare con qualcosa di simile maxFactor :: (Integral a) => a -> ... poi qualcosa d'altro? Tuttavia, se questo è il caso, allora perché questo codice viene compilato poiché il rendimento di maxFactor può essere x o head, che quando si segue questa linea di ragionamento, non ha lo stesso tipo?

Cosa mi manca qui?

Grazie per eventuali ingressi in anticipo!

+1

Questo tipo di problema può presentarsi in un modo molto più semplice. Sospetto (ma non sono esperto) che possa accadere ogni volta che il correttore di tipi non può ridurre sufficientemente un'espressione. Ad esempio, foo x = 1 + x; bar = foo head - fallirà, ma foo x = 1 + x; bar x = foo head - verrà compilato. – Sarah

+0

@Sarah: l'esempio fornito non digita a causa della limitazione del monomorfismo; se aggiungete il pragma, significa che c'è un piccolo problema: GHCi digita 'Num ([a] → a) ⇒ [a] → a' e non puoi dichiarare' bar' con questo tipo, avresti bisogno di FlexibleContexts per quello). – Vitus

+0

Per quello che vale, se compili con '-Wall' (o aggiungilo alle tue opzioni ghci predefinite, in modo che ghci" compili "con' -Wall') riceverai un avviso perché non hai inserito un tipo firma su 'maxFactor'. Quindi, presumibilmente, scriverai 'maxFactor :: Integral a => a -> a' e non riuscirà a compilare. – MatrixFrog

risposta

9

nel maxFactor il compilatore ne deduce che la funzione argomento x ha necessariamente dello stesso tipo di head (nel vostro if clausola). Dal momento che chiami anche fac su x (che a sua volta chiama mod) deduce che x è anche un tipo di classe Integral. Di conseguenza, il compilatore deduce il tipo

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a 

che richiede un po head -come e intero come argomento ... che è improbabile che sia una cosa reale.

Penso che il fatto di poter caricare quel codice in GHCi sia più una stranezza dell'interprete. Se stavi compilando il codice sopra, fallirebbe.

Modifica: Suppongo che il controllo del tipo possa dare un senso al codice, tuttavia probabilmente non esiste un modo ragionevole di utilizzarlo.

+0

In realtà potrebbe compilare (La mia versione è 7.2.1) :(Questo è un bug in GHC ora? Mi chiedo ... Ma ancora, grazie! –

+0

@ZiyaoWei non se si tenta di aggiungere quelle dichiarazioni di tipo inferito. – soulcheck

+4

@ZiyaoWei : Non è un bug, GHC non può sapere che non ci sarà mai una funzione '[a] -> a' che è un'istanza di' Integral'. – leftaroundabout

11

Come avete notato correttamente, l'uso della funzione fac all'interno di maxFactor aggiunge un vincolo Integral a dal tipo di x. Quindi x deve essere di tipo Integral a => a.

Inoltre, il compilatore vede che maxFactor o restituisce head, che ha digitare [a]->a o x. Pertanto x deve avere il tipo più specifico Integral ([a]->a) => ([a]->a), e così maxFactor ha digitare

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> ([a] -> a) 

che è esattamente quello che abbiamo ottenuto. Non c'è nulla di "sbagliato" con questa definizione finora. Se sei riuscito a scrivere un'istanza di Integral tipo ([a]->a) potresti invocare maxFactor senza problemi. (Ovviamente maxFactor non funzionerebbe come previsto.)