2012-04-29 1 views
5

Je ne comprends pas pourquoi la fonction suivante fonctionne:Confusion avec inférence de type Haskell

isLongerThanN :: Integral n => n -> [a] -> Bool 
isLongerThanN n xs = length xs > fromIntegral n 

mais les suivantes ne:

isLongerThanN' :: Integral n => n -> [a] -> Bool 
isLongerThanN' n xs = length xs > n 

qui jette l'erreur

Could not deduce (n ~ Int) 
    from the context (Integral n) 
     bound by the type signature for 
       isLongerThanN' :: Integral n => n -> [a] -> Bool 
     at blah.hs:140:1-35 
     `n' is a rigid type variable bound by 
      the type signature for 
      isLongerThanN' :: Integral n => n -> [a] -> Bool 
      at blah.hs:140:1 
    In the second argument of `(>)', namely `n' 
    In the expression: length xs > n 
    In an equation for `isLongerThanN'': 
     isLongerThanN' n xs = length xs > n 

(que j'ai probablement mal compris)

Si quelque chose, je m'attendrais à ce que ce soit l'inverse, puisque fromIntegral élargit effectivement le type variable n.

+8

Ne pas écrire 'si foo puis Vrai autre FALSE'. C'est la même chose que "foo". – hammar

+1

vous avez raison, merci; Je l'ai modifié, mais ce n'est pas la question – Inept

+4

C'est pourquoi il ne l'a pas posté comme réponse ... – Jasper

Répondre

12

Considérons l'expression qui ne fonctionne pas

isLongerThanN' :: Integral n => n -> [a] -> Bool 
isLongerThanN' n xs = length xs > n 

n peut être tout type d'entier-y, de sorte qu'il peut être passé un Integer ou Word ou Int. (>) a le type Ord a => a -> a -> Bool donc ses deux opérandes gauche et droit doivent être du même type. length xs renvoie un Int donc ce type doit être cela. Mais, n peut être n'importe quel Integral, pas nécessairement Int, donc nous avons besoin d'un moyen de permettre n à être converti en un Int. C'est ce que fait fromIntegral (le fait que cela permette aussi n d'être n'importe quel Num est fondamentalement non pertinent).

Nous pourrions étendre la version de travail pour ressembler à:

toInt :: Integral n => n -> Int 
toInt = fromIntegral 

isLongerThanN :: Integral n => n -> [a] -> Bool 
isLongerThanN n xs = length xs > toInt n 

ce qui le rend plus clair que nous utilisons une version spécialisée de fromIntegral.

(Notez que isLongerThanN n xs = fromIntegral (length xs) > n fonctionne également, car elle permet le résultat de length pour correspondre avec le type de n.)

+2

Cependant, notez que le choix de celui que vous convertissez peut affecter le résultat; avec le dernier exemple 'isLongerThanN (0 :: Word8) [1..256] == False' en raison d'un débordement. – hammar

+0

Oh d'accord, je comprends. Merci beaucoup. Pourquoi la version non-fonctionnelle ne fonctionnait pas n'était pas le problème pour moi, mais je lisais la signature de type fromIntegral :: (Num b, Integral a) => a -> b à tort. – Inept