Warum erzeugt dieser Haskell-Code den Fehler "unendlicher Typ"?

81

Ich bin neu in Haskell und habe den Fehler "Ich kann keinen unendlichen Typ konstruieren", den ich nicht verstehen kann.

Darüber hinaus konnte ich keine gute Erklärung dafür finden, was dieser Fehler überhaupt bedeutet. Wenn Sie also über meine grundlegende Frage hinausgehen und den Fehler "Unendlicher Typ" erklären könnten, würde ich ihn wirklich begrüßen.

Hier ist der Code:

intersperse :: a -> [[a]] -> [a]

-- intersperse '*' ["foo","bar","baz","quux"] 
--  should produce the following:
--  "foo*bar*baz*quux"

-- intersperse -99 [ [1,2,3],[4,5,6],[7,8,9]]
--  should produce the following:
--  [1,2,3,-99,4,5,6,-99,7,8,9]

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:y:xs) = x:s:y:intersperse s xs

Und hier ist der Fehler beim Versuch, ihn in den Interpreter zu laden:

Prelude> :load ./chapter.3.ending.real.world.haskell.exercises.hs
[1 of 1] Compiling Main (chapter.3.ending.real.world.haskell.exercises.hs, interpreted )

chapter.3.ending.real.world.haskell.exercises.hs:147:0:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `intersperse'
Failed, modules loaded: none.

Vielen Dank.

- -

Hier einige korrigierte den Code und eine allgemeine Richtlinie für den Umgang mit dem Fehler "Unendlicher Typ" in Haskell:

Code korrigiert

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) =  x ++ s:intersperse s xs 

Was war das Problem:

Meine Typensignatur besagt, dass der zweite Parameter, der eingestreut werden soll, eine Liste von Listen ist . Wenn ich ein Muster mit "s (x: y: xs)" übereinstimmte, wurden x und y daher zu Listen . Und doch behandelte ich x und y als Elemente, nicht als Listen.

Richtlinie für den Umgang mit dem Fehler "Unendlicher Typ":

Wenn Sie diesen Fehler erhalten, haben Sie meistens die Typen der verschiedenen Variablen vergessen, mit denen Sie sich befassen, und Sie haben versucht, eine Variable so zu verwenden, als wäre sie ein anderer Typ als der, der sie ist. Schauen Sie sich genau an, um welchen Typ es sich handelt und wie Sie ihn verwenden. Dadurch wird das Problem normalerweise aufgedeckt.

Charlie Flowers
quelle
2
Ein weiterer guter Tipp: Deklarieren Sie die Typen explizit. Dies gibt dem Compiler etwas, gegen das er prüfen kann.
Paul Johnson
3
Dies löst das Problem, aber warum sagt der Compiler "Kann keinen unendlichen Typ konstruieren?". Was bedeutet das? Wenn das Problem darin besteht, dass Sie versuchen, Operationen für Typen auszuführen, die diese Operationen nicht unterstützen, warum sagt der Compiler so etwas nicht?
freedrull
11
+1 für die Struktur der Frage (Frage - korrigiert - Problem war - Richtlinie)
Dacav
2
@freedrull: Der Fehler ist so formuliert, weil ich dem Compiler gesagt habe, dass der Typparameter "a" mit einer "Liste von a" "gefüllt" werden soll. Das ist so, als würde ich sagen, dass meine Kaffeetasse ein paar Kopien meiner Kaffeetasse enthält. Es ist wirklich eine rekursive Definition, die keinen Sinn ergibt (oder zumindest in Haskell als ungültig definiert ist). Also sagt es mir: "Kann keinen unendlichen Typ konstruieren". Die Sache ist, ich könnte andere Dinge mit diesem Typparameter machen, die auf a basieren. Zum Beispiel könnte ich diesen Typparameter mit "Vielleicht a" füllen. Die Art von Dingen, die ich getan habe, ist in Ordnung, aber die spezifischen Dinge, die ich getan habe, sind nicht in Ordnung.
Charlie Flowers
1
@freedrull: Der Compiler hat bemerkt, dass der Code eine Reihe von Dingen mit verwandten Werten ausführt a, von denen jeder für sich in Ordnung wäre. Es kann also nicht auf einen von ihnen zeigen und sagen "das ist eine nicht unterstützte Operation für diesen Typ". Aber zusammen fügen sie befriedigend für einen Typ einer Anforderung bis a = [a]. Der Compiler weiß, dass dies unmöglich ist, und sagt Ihnen dies. Es ist nicht bekannt, welche Teile des Codes, die zu dieser Anforderung geführt haben, die falschen Teile sind. Das hängt davon ab , was Sie beabsichtigt , den Code zu verstehen.
Ben

Antworten:

36

Das Problem liegt in der letzten Klausel, in der Sie x und y als Elemente behandeln, während es sich um Listen handelt. Das wird funktionieren:

intersperse _ [] = []
intersperse _ [x] = x 
intersperse s (x:y:xs) = x ++ [s] ++ y ++ intersperse s xs

Der unendliche Typfehler tritt auf, weil der Operator: den Typ a -> [a] -> [a] hat, während Sie ihn als [a] -> a -> [a] behandeln, was bedeutet, dass [a] mit identifiziert werden muss a, was bedeuten würde, dass a eine unendlich verschachtelte Liste ist. Das ist nicht erlaubt (und sowieso nicht das, was du meinst).

Bearbeiten: Es gibt auch einen anderen Fehler im obigen Code. Es sollte sein:

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) = x ++ [s] ++ intersperse s xs
Stephan202
quelle
1
Vielen Dank. Ich habe beide herausgefunden und bin dann hierher zurückgekommen und habe Ihre Antwort gesehen, was für mich eine hervorragende Bestätigung war. Du hast meinen Fehler auch besser behoben als ich. Mein Fehler war, dass ein Trennzeichen zwischen y und xs übersprungen wurde. Um dies zu beheben, habe ich eine weitere Ebene der Musterübereinstimmung eingeführt: Intersperse s (x: y: []) = x ++ s: y Intersperse s (x: y: xs) = Intersperse s [x, y] ++ s: intersperse s xs Aber es sieht so aus, als hätten Sie meinen Fehler behoben, ohne dass Sie dieses zusätzliche Level benötigen.
Charlie Flowers
2
Hier ist die Lektion, die ich lerne: "Wenn Sie mit einem Fehler" Unendlicher Typ "konfrontiert werden, vergessen Sie wahrscheinlich, mit welchen Typen Sie es zu tun haben, und tun daher etwas, was Sie nicht vorhatten. Sehen Sie sich genau an, welchen Typ jede Ihrer Variablen hat ist, und das wird in der Regel das Problem aufdecken. " Gibt es etwas, das Sie hinzufügen oder ändern würden?
Charlie Flowers
Das ist sicherlich richtig, und daran würde ich nichts ändern. Unendliche Typen sind nicht zulässig, und daher bedeutet ein Fehler beim unendlichen Typ, dass eine Funktion irgendwo ein Argument mit einem falschen Typ empfängt. Viel Glück mit RWH :)
Stephan202
where you treat x and y as elements, while they are lists.Warum sind sie Listen, das hast du nicht erklärt? In x:xs, xist ein Element, nicht wahr? Ich hatte gehofft, dass es x:y:xsauch so sein wird. Wenn es sich um Listen handelt, wie werden sie aufgeteilt und enthalten wie viele Elemente? Ich denke eins?
Nawaz
6

Oft kann das Hinzufügen einer expliziten Typdefinition die Typfehlermeldung des Compilers sinnvoller machen. In diesem Fall verschlimmert die explizite Eingabe die Fehlermeldung des Compilers.

Schauen Sie, was passiert, wenn ich ghc die Art der Streuung erraten lasse:

Occurs check: cannot construct the infinite type: a = [a]
  Expected type: [a] -> [[a]] -> [[a]]
  Inferred type: [a] -> [[a]] -> [a]
In the second argument of `(:)', namely `intersperse s xs'
In the second argument of `(:)', namely `y : intersperse s xs'

Das deutet eindeutig auf den Fehler im Code hin. Mit dieser Technik müssen Sie nicht auf alles starren und über die Typen nachdenken, wie andere vorgeschlagen haben.

Joey
quelle
3

Ich kann mich irren, aber es scheint, dass Sie versuchen, ein schwierigeres Problem zu lösen. Ihre Version von verteilt intersperseden Wert nicht nur auf das Array, sondern glättet ihn auch um eine Ebene.

Das ListModul in Haskell bietet tatsächlich eine Zwischenfunktion. Es gibt den Wert ein, der zwischen jedem Element in der Liste angegeben ist. Zum Beispiel:

intersperse 11 [1, 3, 5, 7, 9] = [1, 11, 3, 11, 5, 11, 7, 11, 9]
intersperse "*" ["foo","bar","baz","quux"] = ["foo", "*", "bar", "*", "baz", "*", "quux"]

Ich gehe davon aus, dass Sie dies tun möchten, weil mein Professor dies von uns wollte, als ich Haskell lernte. Ich könnte natürlich total raus sein.

Samir Talwar
quelle
1
Danke für den Kommentar. In diesem Fall möchte ich es jedoch um eine Ebene reduzieren, da ich Übung 7 ab dem Ende von Kapitel 3 von "Real World Haskell" mache.
Charlie Flowers
Erwischt. Wenn ich das Buch hätte, hätte ich es vor dem Schreiben überprüft. Leider konnte ich nur raten. Ich bin froh, dass du es trotzdem sortiert hast. :-)
Samir Talwar
5
Der Inhalt des Buches wird online frei verfügbar gemacht: book.realworldhaskell.org
Stephan202
Ausgezeichnet. Lesezeichen. Vielen Dank für den Link - ich werde nächstes Jahr in den Haskell-Labors helfen, und dies wird zweifellos beim Auffrischen nützlich sein.
Samir Talwar
0

Auch ich fand dies, was die Bedeutung des Fehlers erklärt.

Jedes Mal, wenn der Interpreter / Compiler diesen Fehler ausgibt, verwende ich ein typparametrisiertes Tupel als formalen Parameter. Alles funktioniert korrekt, indem die Typdefinition der Funktion entfernt wird, die Typvariablen enthielt.

Ich kann immer noch nicht herausfinden, wie ich das Problem beheben und die Definition des Funktionstyps beibehalten kann.

Dacav
quelle