2012-04-10 7 views
11

Ich war so müde, dass ich schrieb den folgenden Code (zeige geändert, nur die Verwirrung):Haskell: Warum gibt es keinen Typunterschied (und warum kompiliert er)?

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 

jedoch diese Last in GHCI (und kompiliert) einwandfrei. Als ich maxFactor 1 ausgeführt, klagt es (natürlich):

<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 

Aber ich dieses Verhalten nicht verstehen:

fac 's Typ:

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

während maxFactor' s Typ ist:

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

Bedeutet dies nicht th e folgendes:

  1. der erste Eingang mit facIntegral von typeclass sein muß (z.B. fac 10);
  2. da in der Definition von maxFactor gibt es fac x, x muss auch seine typeclass Integral somit maxFactor ‚s Art mit so etwas wie maxFactor :: (Integral a) => a -> beginnen würde ... dann noch etwas anderes? Wenn dies jedoch der Fall ist, warum kompiliert dieser Code seit der Rückkehr von maxFactorx oder head, die, wenn diese Argumentation folgt, nicht den gleichen Typ?

Was fehlt mir hier?

Vielen Dank für alle Eingaben im Voraus!

+1

Diese Art von Problem kann in einer viel einfacheren Art und Weise auftreten. Ich vermute (aber ich bin kein Experte), dass es passieren kann, wenn der Typ-Checker einen Ausdruck nicht ausreichend reduzieren kann. Zum Beispiel foo x = 1 + x; bar = foo head - wird fehlschlagen, aber foo x = 1 + x; bar x = foo head - wird kompiliert. – Sarah

+0

@Sarah: Das von Ihnen angegebene Beispiel wird wegen der Monomorphieeinschränkung nicht überprüft. Wenn du Pragma hinzufügst, gibt es einen Tippfehler (es gibt jedoch ein kleines Problem: GHCi leitet den Typ 'Num ([a] → a) ⇒ [a] → a' ein und du kannst mit diesem Typ nicht' bar' deklarieren, du brauchst FlexibleContexts dafür). – Vitus

+0

Für was es wert ist, wenn Sie mit "-Wall" kompilieren (oder fügen Sie das zu Ihren Standard-Ghci-Optionen, so dass Ghci "kompiliert" mit "-Wall") erhalten Sie eine Warnung, weil Sie keinen Typ gesetzt haben Signatur auf 'maxFactor'. Dann schreiben Sie vermutlich 'maxFactor :: Integral a => a -> a 'und es wird nicht kompiliert. – MatrixFrog

Antwort

9

in maxFactor folgert der Compiler, dass das Funktionsargument x unbedingt den gleichen Typ wie head (in Ihrer if Klausel) hat. Da Sie auch fac auf x (die wiederum ruft mod ruft) darauf hin, dass x ist auch einige Integral Klassenart. Folglich schließt der Compiler den Typ

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

, die einige head -ähnliche und Integer-like-Argument ... was unwahrscheinlich ist eine reale Sache zu sein.

Ich denke, die Tatsache, dass Sie diesen Code in GHCi laden können, ist mehr eine Eigenart des Interpreters. Wenn Sie nur den obigen Code kompilieren, würde es fehlschlagen.

Edit: Ich denke, das Problem ist, dass der Typ Checker Sinn Ihres Codes machen kann, aber es gibt wahrscheinlich keine vernünftige Möglichkeit, es zu verwenden.

+0

Eigentlich könnte es kompilieren (Meine Version ist 7.2.1) :(Ist das ein Fehler in GHC jetzt? Ich frage mich ... Aber immer noch, danke! –

+0

@ZiyaoWei nicht, wenn Sie versuchen, diese abgeleiteten Typ Deklarationen hinzuzufügen. – soulcheck

+4

@ZiyaoWei : Es ist kein Bug. GHC kann nicht wissen, dass es niemals eine Funktion '[a] -> a' geben wird, die eine Instanz von' Integral' ist. – leftaroundabout

11

Wie Sie richtig bemerkt haben, die Verwendung von Funktion fac innerhalb von maxFactor fügt eine Integral a Einschränkung für die Art von x. So muss x vom Typ Integral a => a sein.

Zusätzlich sieht der Compiler, der entweder maxFactorhead zurückgibt, welches [a]->a oder x eingeben. Daher muss x haben die spezifischeren Typ Integral ([a]->a) => ([a]->a), und so maxFactor hat

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

Typ das ist genau das, was du hast. Mit dieser Definition ist bisher nichts "falsch". Wenn Sie eine Instanz Integral Typ ([a]->a) schreiben konnten, konnten Sie problemlos maxFactor aufrufen. (Offensichtlich maxFactor würde nicht wie erwartet funktionieren.)