2012-04-29 14 views
5

Ich verstehe nicht, warum die folgende Funktion funktioniert:Verwirrung mit Inferenz Haskell Typ

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

aber folgendes nicht:

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

, die den Fehler wirft

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 

(was ich wahrscheinlich falsch verstanden habe)

Wenn überhaupt, würde ich erwarten, dass es andersherum ist, da vonIntegral effektiv Variable n Typ zu erweitern ist.

+8

Schreiben Sie nicht 'wenn foo dann wahr sonst false'. Es ist das gleiche wie nur 'foo'. – hammar

+1

du hast recht, danke; Ich habe es geändert, aber das ist nicht die Frage – Inept

+4

Deshalb hat er es nicht als Antwort posten ... – Jasper

Antwort

12

Betrachten wir den Ausdruck, der nicht

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

n kann eine beliebige ganze Zahl y-Typ sein, nicht funktioniert, so dass es eine oder IntegerWordInt oder übergeben werden können. (>) hat den Typ , so dass sowohl der linke als auch der rechte Operand vom selben Typ sein müssen. length xs gibt eine Int zurück, also muss dieser Typ das sein. Aber n kann jeder sein Integral, nicht unbedingt Int, so müssen wir einen Weg n zu einem Int konvertiert werden. Dies ist, was fromIntegral tut (die Tatsache, dass es auch n zu jeder Num ist im Grunde irrelevant ist).

Wir könnten die Arbeitsversion erweitern aussehen:

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

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

, die es klarer machen, dass wir eine spezielle Version von fromIntegral verwenden.

(Beachten Sie, dass isLongerThanN n xs = fromIntegral (length xs) > n auch funktioniert, weil es das Ergebnis von length passen mit der Art der n erlaubt.)

+2

Beachten Sie, dass die Wahl, die Sie konvertieren, das Ergebnis beeinflussen kann; mit dem letzten Beispiel 'isLongerThanN (0 :: Word8) [1..256] == False 'wegen Überlauf. – hammar

+0

Oh okay, ich verstehe es. Danke vielmals. Warum die nicht funktionierende Version nicht funktioniert, war nicht das Problem für mich, aber ich las die Typensignatur von Integral :: (Num b, Integral a) => a -> b falsch. – Inept