Warum kann Haskell eine wiederholte Auswertung ohne die Einschränkung des Monomorphismus nicht vermeiden?

14

Ich habe neulich gerade das Lernen von Youahaskell beendet und habe versucht, die Monomorphismus-Einschränkung zu verstehen, wie sie im Haskell-Wiki beschrieben wird . Ich denke, ich verstehe, wie der MR wiederholte Auswertungen verhindern kann, aber ich verstehe nicht, warum diese wiederholten Auswertungen mit weitaus einfacheren Mitteln nicht vermieden werden können.

Das konkrete Beispiel, an das ich denke, ist das, das im Wiki verwendet wird:

f xs = (len,len)
  where
    len = genericLength xs

Wo genericLengthist der Typ Num a => [b] -> a.

Offensichtlich muss genericLength xsnur einmal berechnet werden, um auszuwerten (len,len), da es die gleiche Funktion mit den gleichen Argumenten ist. Und wir brauchen keine Aufrufe von fzu sehen, um das zu wissen. Warum kann Haskell diese Optimierung nicht durchführen, ohne eine Regel wie die MR einzuführen?

Die Diskussion auf dieser Wiki-Seite sagt mir, dass es etwas mit der Tatsache zu tun hat, dass Numes sich eher um eine Typenklasse als um einen konkreten Typ handelt. Sollte es jedoch beim Kompilieren nicht offensichtlich sein, dass eine reine Funktion denselben Wert zurückgibt. -und damit die gleiche konkrete Art von Num - wenn zweimal die gleichen Argumente gegeben werden?

Ixrec
quelle

Antworten:

11

Es ist derselbe Funktionsname mit denselben Argumenten, aber möglicherweise unterschiedlichen Rückgabetypen und Implementierungen, da er polymorph ist. Das heißt, wenn es in einem Kontext aufgerufen wird, der einen (Int, MyWeirdCustomNumType)Rückgabetyp erwartet , muss es zweimal ausgewertet werden, da sich die Implementierung von (+)in Intvöllig von der Implementierung von (+)in unterscheidet MyWeirdCustomNumType. Sie müssen irgendwann physisch anderen Code ausführen.

Deshalb ist es wichtig, dass Numes sich um eine Typenklasse handelt. Dies bedeutet, dass Sie unterschiedliche Implementierungen für unterschiedliche Typen haben. Dies bedeutet auch, dass fin einer Bibliothek zum Zeitpunkt der Kompilierung nicht alle Kombinationen von Typen bekannt sind, die möglicherweise zurückgegeben werden müssen.

Ja, Sie müssen die Aufrufe von sehen, um fzu wissen, welche Rückgabetypen verwendet werden sollen. In den meisten Fällen würde man erwarten, dass sie gleich sind, weshalb die Monomorphismus-Beschränkung standardmäßig aktiviert ist. Sie kann in seltenen Fällen deaktiviert werden, wenn dies nicht der Fall ist. In der Praxis überlassen Programmierer solche Situationen sowieso nicht der Typinferenz.

Karl Bielefeldt
quelle
Ich hatte die Möglichkeit nicht in Betracht gezogen f [] :: (Int, Float). Jetzt macht es vollkommen Sinn. Vielen Dank.
Ixrec
1
It's the same function name, with the same arguments, but potentially different return types and implementations, because it's polymorphic.Ich denke, die bessere Sichtweise ist, dass die Typeclass-Instanz tatsächlich ein zusätzliches Argument ist genericLengthund der Compiler nicht davon überzeugt ist, dass es in beiden Aufrufen die gleichen Argumente gibt.
Doval
Kurze Nebenfrage. Wenn MonomorphismRestriction deaktiviert ist, Sie aber später Folgendes ausgeführt haben: Ist es möglich, diese Aufrufsite a = uncurry (==) $ f [1, 2, 3]so zu optimieren, dass nur die Länge von [1, 2, 3]einmal überprüft wird ? Wenn ja, dann bin ich wirklich verwirrt, was die Monomorphismus-Beschränkung tatsächlich für Sie bedeutet. Wenn nein, warum nicht?
Semikolon