Es scheint, dass alle neuen Programmiersprachen oder zumindest diejenigen, die populär geworden sind, Typinferenz verwenden. Sogar Javascript hat Typen und Typinferenz durch verschiedene Implementierungen (Acscript, typescript etc). Es sieht toll aus, aber ich frage mich, ob es Kompromisse gibt oder warum Java oder die alten guten Sprachen keine Typinferenz haben
- Wenn Sie eine Variable in Go deklarieren, ohne ihren Typ anzugeben (mithilfe von var ohne Typ oder der Syntax: =), wird der Typ der Variablen aus dem Wert auf der rechten Seite abgeleitet.
- D ermöglicht das Schreiben großer Codefragmente ohne redundante Typangabe, wie dies bei dynamischen Sprachen der Fall ist. Andererseits werden durch statische Inferenz Typen und andere Codeeigenschaften abgeleitet, wodurch sowohl die statische als auch die dynamische Welt optimal genutzt werden.
- Die Typinferenzmaschine in Rust ist ziemlich schlau. Es ist mehr als nur die Art des r-Werts während einer Initialisierung zu betrachten. Es sieht auch so aus, als würde die Variable später verwendet, um auf ihren Typ zu schließen.
- Swift verwendet die Typinferenz, um den entsprechenden Typ zu ermitteln. Mit der Typinferenz kann ein Compiler den Typ eines bestimmten Ausdrucks automatisch ableiten, wenn er Ihren Code kompiliert, indem er einfach die von Ihnen angegebenen Werte untersucht.
programming-languages
type-systems
Der User ohne Hut
quelle
quelle
var
dass dies die Lesbarkeit beeinträchtigen kann.var
und C ++auto
) und Typinferenz (bidirektional, wie Haskelllet
). Im ersteren Fall kann der Typ eines Namens nur von seinem Initialisierer abgeleitet werden - seine Verwendung muss dem Typ des Namens folgen. Im letzteren Fall kann der Typ eines Namens auch aus seiner Verwendung abgeleitet werden. Dies ist hilfreich, da Sie[]
unabhängig vom Elementtyp einfach für eine leere Sequenz odernewEmptyMVar
für eine neue nullveränderliche Referenz schreiben können , unabhängig vom Referenten Art.Antworten:
Haskell Typ - System ist vollständig inferrable (abgesehen von polymorpher Rekursion, bestimmte Spracherweiterungen und die gefürchtete Monomorphie Beschränkung ), noch Programmierer immer noch häufig Typenannotationen im Quellcode zur Verfügung stellen , auch wenn sie nicht brauchen. Warum?
map :: (a -> b) -> [a] -> [b]
. Die allgemeinere Form (fmap :: Functor f => (a -> b) -> f a -> f b
) gilt für alleFunctor
s, nicht nur für Listen. Aber es war der Meinung, dassmap
dies für Anfänger leichter zu verstehen wäre, und so lebt es neben seinem größeren Bruder weiter.Im Großen und Ganzen sind die Nachteile eines statisch getippten, aber nicht ableitbaren Systems fast dieselben wie die Nachteile des statischen Tippens im Allgemeinen. Eine abgenutzte Diskussion auf dieser Website und auf anderen (Googeln mit "statischen Tippnachteilen" bringt Ihnen Hunderte Seiten von Flammenkriegen). Natürlich werden einige der genannten Nachteile durch die geringere Anzahl von Typanmerkungen in einem inferrierbaren System verbessert. Außerdem hat die Typinferenz ihre eigenen Vorteile: Ohne die Typinferenz wäre eine lochgesteuerte Entwicklung nicht möglich.
Java * beweist, dass eine Sprache, die zu viele Typanmerkungen erfordert, ärgerlich wird, aber mit zu wenig verlieren Sie die oben beschriebenen Vorteile. Sprachen mit Opt-Out-Typ-Inferenz stellen ein annehmbares Gleichgewicht zwischen den beiden Extremen her.
* Sogar Java, dieser große Sündenbock, führt eine gewisse lokale Inferenz durch. In einer Anweisung wie
Map<String, Integer> = new HashMap<>();
muss der generische Typ des Konstruktors nicht angegeben werden. Auf der anderen Seite sind ML- ähnliche Sprachen in der Regel global nicht ableitbar.quelle
Functor
. Listetmap
nicht erfahrene Haskeller auf und ist ihnen mit größerer Wahrscheinlichkeit vertraut.var
als Beispiel für Typinferenz betrachten?var
ist ein gutes Beispiel.x
; In letzterem gibt es keinen zu bestimmenden Typ, alle Typen sind bekannt und Sie müssen nur prüfen, ob der Ausdruck sinnvoll ist. Der Unterschied wird wichtiger, wenn Sie an trivialen Beispielen vorbeigehen, undx
wird an mehreren Stellen verwendet. Der Compiler muss dann die Stellen überprüfenx
, an denen ermittelt wird. 1) Ist es möglich,x
einen Typ so zuzuweisen, dass der Code eine Typprüfung durchführt? 2) Wenn ja, welchen allgemeinen Typ können wir zuordnen?new HashMap<>();
Syntax nur in Java 7 hinzugefügt wurde und die Lambdas in Java 8 eine Menge "realer" Typinferenzen ermöglichen.In C # tritt eine Typinferenz zur Kompilierungszeit auf, sodass die Laufzeitkosten Null sind.
Wird aus Gründen des Stils
var
für Situationen verwendet, in denen es entweder unpraktisch oder unnötig ist, den Typ manuell anzugeben. Linq ist eine solche Situation. Ein anderer ist:ohne das Sie Ihren wirklich langen Typnamen (und die Typparameter) wiederholen würden, anstatt einfach zu sagen
var
.Verwenden Sie den tatsächlichen Namen des Typs, wenn dieser explizit angegeben wird, um die Übersichtlichkeit des Codes zu verbessern.
Es gibt Situationen, in denen keine Typinferenz verwendet werden kann, z. B. Member-Variablendeklarationen, deren Werte zum Zeitpunkt der Erstellung festgelegt werden, oder in denen Sie wirklich möchten, dass Intellisense ordnungsgemäß funktioniert (die IDE von Hackerrank erkennt die Member der Variablen nur, wenn Sie den Typ explizit deklarieren). .
quelle
Gute Frage!
Und es gibt noch mehr esoterische Sprachen, die ihre Verrücktheit nicht ohne explizite Typanmerkungen vollbringen können. Bisher gibt es keine, von denen ich weiß, dass sie allgemein / populär / vielversprechend genug sind, um sie zu erwähnen, außer im Vorbeigehen.
quelle
var foo = x => x;
scheitert, weil die Sprachex
hier schließen muss und nichts weiter zu tun hat. Wenn die Lambdas erstellt werden, werden sie als explizit typisierte DelegatenFunc<int, int> foo = x => x
in CIL erstellt, so wieFunc<int, int> foo = new Func<int, int>(x=>x);
das Lambda als generierte explizit typisierte Funktion erstellt wird. Für mich ist der Rückschluss auf die Art einx
x => x
sind im Lambda selbst enthalten - es verweist nicht auf Variablen aus dem umgebenden Bereich. Jede vernünftige funktionale Sprache würde richtig schließen , dass seine Art ist „für alle Artena
,a -> a
“. Ich denke, was DeadMG zu sagen versucht, ist, dass dem Typensystem von C # die Principal-Type-Eigenschaft fehlt, was bedeutet, dass es immer möglich ist, den allgemeinsten Typ für einen Ausdruck herauszufinden. Es ist sehr leicht zu zerstören.Java ist hier eher die Ausnahme als die Regel. Selbst C ++ (von dem ich glaube, dass es eine "gute alte Sprache" ist :)) unterstützt
auto
seit dem C ++ 11-Standard die Typinferenz mit dem Schlüsselwort. Es funktioniert nicht nur mit Variablendeklaration, sondern auch als Funktionsrückgabetyp, was besonders bei einigen komplexen Vorlagenfunktionen nützlich ist.Implizite Typisierung und Inferenz haben viele gute Anwendungsfälle, und es gibt auch einige Anwendungsfälle, bei denen Sie dies wirklich nicht tun sollten. Dies ist manchmal Geschmackssache und auch Gegenstand von Debatten.
Dass es aber zweifellos gute Anwendungsfälle gibt, ist für sich genommen ein legitimer Grund für jede Sprache, diese umzusetzen. Es ist auch kein schwer zu implementierendes Feature, keine Laufzeitstrafe und hat keinen wesentlichen Einfluss auf die Kompilierzeit.
Ich sehe keinen wirklichen Nachteil darin, dem Entwickler die Möglichkeit zu geben, Typinferenz zu verwenden.
Einige Antwortende überlegen, wie gut es manchmal ist, explizit zu tippen, und sie haben mit Sicherheit Recht. Wird die implizite Typisierung jedoch nicht unterstützt, bedeutet dies, dass eine Sprache die ganze Zeit explizite Typisierung erzwingt.
Der eigentliche Nachteil ist also, dass eine Sprache keine implizite Typisierung unterstützt, da hiermit angegeben wird, dass es keinen legitimen Grund für den Entwickler gibt, diese zu verwenden, was nicht der Fall ist.
quelle
Der Hauptunterschied zwischen einem Inferenzsystem vom Typ Hindley-Milner und einem Inferenzsystem vom Typ Go ist die Richtung des Informationsflusses. In HM fließen Typinformationen über die Vereinheitlichung vorwärts und rückwärts. Geben Sie in "Gehe zu" den Informationsfluss nur vorwärts ein: Er berechnet nur vorwärts gesetzte Ersetzungen.
HM-Typinferenz ist eine großartige Innovation, die mit polymorph getippten funktionalen Sprachen gut funktioniert, aber Go-Autoren würden wahrscheinlich argumentieren, dass es zu viel zu tun versucht:
Die Tatsache, dass Informationen sowohl vorwärts als auch rückwärts fließen, bedeutet, dass die Inferenz des HM-Typs eine sehr nichtlokale Angelegenheit ist. Ohne Typanmerkungen kann jede Codezeile in Ihrem Programm zur Eingabe einer einzelnen Codezeile beitragen. Wenn Sie nur eine Vorwärtsersetzung haben, wissen Sie, dass die Quelle eines Typfehlers im Code liegen muss, der Ihrem Fehler vorangeht. nicht der Code, der danach kommt.
Bei der Inferenz von HM-Typen neigen Sie dazu, in Einschränkungen zu denken: Wenn Sie einen Typ verwenden, schränken Sie die möglichen Typen ein. Am Ende des Tages kann es einige Typvariablen geben, die völlig uneingeschränkt bleiben. Die Erkenntnis der HM-Typinferenz ist, dass diese Typen wirklich keine Rolle spielen und daher zu polymorphen Variablen verarbeitet werden. Dieser zusätzliche Polymorphismus kann jedoch aus einer Reihe von Gründen unerwünscht sein. Erstens, wie einige Leute herausgestellt haben, könnte dieser zusätzliche Polymorphismus unerwünscht sein: HM schließt einen gefälschten, polymorphen Typ für einen gefälschten Code ab und führt später zu seltsamen Fehlern. Zweitens kann dies Konsequenzen für das Laufzeitverhalten haben, wenn ein Typ polymorph bleibt. Zum Beispiel ist ein zu polymorphes Zwischenergebnis der Grund, warum 'zeigen. read 'wird in Haskell als mehrdeutig angesehen; als weiteres Beispiel
quelle
Es schadet der Lesbarkeit.
Vergleichen Sie
vs
Dies ist vor allem dann ein Problem, wenn Sie außerhalb einer IDE wie auf einem Github lesen.
quelle
var
kann dieser verwendet werden, ohne die Lesbarkeit zu beeinträchtigen.var objects = GetBusinessObjects();