Warum kann ich nicht hinzufügen, Integer zu Double in Haskell?
Warum ist es, dass ich tun kann:
1 + 2.0
aber wenn ich versuche:
let a = 1
let b = 2.0
a + b
<interactive>:1:5:
Couldn't match expected type `Integer' with actual type `Double'
In the second argument of `(+)', namely `b'
In the expression: a + b
In an equation for `it': it = a + b
Dieser scheint einfach nur komisch! Macht es überhaupt Reise, die Sie bis?
P. S.: ich weiß, dass "1" und "2.0" sind polymorphe Konstanten. Das ist nicht was mir sorgen macht. Was mich beunruhigt, ist, warum haskell hat eine, was im ersten Fall, aber anderen in der zweiten!
- Wie das meme geht, "braucht mehr
fromIntegral
". - Erinnert mich irgendwie an
x.f()
vsg=x.f; g();
in Javascript. Es nervt, wenn Variablen brechen die substitution model Abstraktion.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie GHCI zu lernen, ein wenig mehr über diese. Verwenden Sie den Befehl
:t
um den Typ eines Ausdrucks.So
1
ist eine Konstante, die sein kann ein beliebiger numerischer Typ (Double
,Integer
usw.)So, in diesem Fall, Haskell inferred der konkrete Typ für
a
istInteger
. Ähnlich, wenn Sie schreibenlet b = 2.0
dann Haskell folgert die ArtDouble
. Mitlet
gemacht Haskell schließen, ein spezifischer Typ als (vielleicht) notwendig war, und das führt zu deinem problem. (Jemand mit mehr Erfahrung als ich, vielleicht als Kommentar, warum dies der Fall ist.) Da(+)
TypNum a => a -> a -> a
, die zwei Argumente müssen den gleichen Typ aufweisen.Beheben Sie das Problem mit der
fromIntegral
Funktion:Diese Funktion wandelt integer-Typen in andere numerische Typen. Zum Beispiel:
let
bewirkt, dass eine bestimmte Art gewählt werden. Sie können dies überschreiben, indem Sie eine Art Unterschrift, oder durch:set -XNoMonomorphismRestriction
im GHCi (oder das entsprechende flag beim kompilieren).()
in die Liste der Standard-Typen.let x = 3
, und eine (monomorphe) - Typ muss ausgewählt werden, fürx
ohne Kontext.Die Typ-Signatur von
(+)
ist definiert alsNum a => a -> a -> a
, was bedeutet, dass es funktioniert auf jedem Mitglied derNum
typeclass, aber beide Argumente müssen vom gleichen Typ sein.Ist hier das problem mit GHCI und es stellt Typen, nicht von Haskell selbst. Wenn Sie entweder Ihre Beispiele in einer Datei (mit
do
für dielet
Ausdrücken), wäre es kompilieren und ausführen in Ordnung, da GHC würde die ganze Funktion als Rahmen, um zu bestimmen, die Typen der Literale1
und2.0
.All das geschieht im ersten Fall ist GHCI ist zu raten, die Arten der zahlen, die Sie eingeben. Die präziseste ist ein
Double
, so dass es gerade davon ausgegangen, der andere war angeblich einDouble
und führt die Berechnung. Jedoch, wenn Sie dielet
Ausdruck, es hat nur eine Reihe von arbeiten, so entscheidet es1
ist einInteger
und2.0
ist einDouble
.EDIT: GHCI ist nicht wirklich "raten", es ist mit sehr spezifischen Typ säumigen Regeln, die definiert sind in der Haskell-Report. Sie können Lesen, ein wenig mehr über das hier.
(+) :: Num a => a -> a -> a
) nicht erlauben. (Es braucht nicht sehr gut zu spielen mit der Typ-Inferenz aber, das ist wahrscheinlich der Grund war es nicht getan.) Auch Ihre Antwort kann klarer werden, wenn Sie ausdrücklich ("erraten", ist nicht gerecht IMHO) erklären Typ ausfallenden und die Tatsache, dass Literale sind polymorph.a
zuDouble
wegen der Art, wie man es verwendet. Allerdings, wenn Sie versuchen, verwenden Siea
einmal in einemInteger
Kontext und einmal in einerDouble
Kontext, erhalten Sie das gleiche problem, weil ohne eine Art Signatur der compiler immer noch versuchen, zu folgern, eine monomorphe Art füra
.a = 1; b = 2.0; useless = div a 3; add = a + b
es nicht kompilieren, weil Sie eine in eineInteger
Umfeld (mitdiv
) und eineDouble
Zusammenhang mitadd
.Das erste funktioniert, weil die numerischen Literale sind polymorph (Sie werden interpretiert als
fromInteger literal
resp.fromRational literal
), also in1 + 2.0
Sie wirklich habenfromInteger 1 + fromRational 2
, in der Abwesenheit von anderen Einschränkungen, das Ergebnis geben standardmäßigDouble
.Die zweite hat nicht funktionieren, weil der monomorphism Einschränkung. Wenn Sie etwas binden, ohne eine Art Unterschrift und mit einem einfachen Muster Bindung (
name = expresion
), wird die entity zugewiesen bekommt eine monomorphe Art. Für die wörtliche1
haben wir eineNum
Einschränkung, also nach der säumige Regeln, seine Art ist standardmäßig aufInteger
in der Bindunglet a = 1
. Ebenso die Bruch-literal-Typ ist standardmäßig aufDouble
.Wird es funktionieren, durch die Art und Weise, wenn Sie
:set -XNoMonomorphismRestriction
im ghci.Den Grund für die monomorphism Einschränkung ist zur Vermeidung des Verlustes von teilen, wenn Sie sehen, ein Wert, der aussieht wie eine Konstante, die Sie nicht erwarten, dass es berechnet werden, mehr als einmal, aber wenn es eine polymorphe Art, es würde neu berechnet werden jedesmal, wenn es benutzt wird.
Andere angesprochen haben, viele Aspekte dieser Frage ganz gut. Ich möchte sagen, ein Wort über die Hintergründe, warum
+
hat der Typ SignaturNum a => a -> a -> a
.Erstens, die
Num
typeclass hat keine Möglichkeit zu konvertieren artbitrary InstanzNum
in ein anderes. Angenommen ich habe einen Datentyp für komplexe zahlen; Sie sind immer noch zahlen, aber Sie können wirklich nicht richtig konvertieren Sie Sie in nur einInt
.Zweitens, welche Art Unterschrift würden Sie bevorzugen?
Nachdem man die anderen Optionen, werden Sie erkennen, dass
a -> a -> a
ist die einfachste Wahl. Polymorphe Ergebnisse (wie im Dritten Vorschlag oben) sind cool, aber manchmal zu allgemein, um verwendet werden, bequem.Drittens, Haskell ist nicht Blub. Die meisten aber wohl nicht alle, Entscheidungen zum design von Haskell nicht berücksichtigt werden, die den Konventionen und Erwartungen der beliebtesten Sprachen. Ich Häufig genießen Sie sagen, dass der erste Schritt zum lernen von Haskell ist, zu verlernen, alles, was Sie denken, Sie wissen über die Programmierung des ersten. Ich bin mir sicher, dass die meisten, wenn nicht alle, erfahrene Haskellers wurden ausgelöst durch die Num typeclass, und verschiedene andere Kuriositäten Haskell, weil die meisten haben gelernt, mehr "mainstream" Sprache erste. Aber seien Sie geduldig, werden Sie schließlich erreichen Haskell nirvana. 🙂