Ich weiß, dass Eiffel (der Progenitor) und Racket beide "Design by Contract" -Funktionen implementiert haben. Leider bin ich mir nicht sicher, wie man sich von den anderen unterscheiden würde. Eiffels DBC ist auf das OOP-Paradigma und die Vererbung angewiesen, aber wie würde Racket, eine ganz andere Sprache, für solch eine Disparität verantwortlich sein?
Zunächst ist Ihre beste Informationsquelle zu diesem Zeitpunkt der Racket Guide , der als einleitender Text anstelle eines Referenzhandbuchs. Insbesondere gibt es ein umfangreiches Kapitel über Verträge , das helfen würde. EDIT: Sieh dir auch die Zeitung an, auf die Robby zeigte, er ist der Hauptvertreter von Racket.
Was Ihre Frage betrifft - ich weiß nicht viel über das Eiffel-Vertragssystem, aber ich denke, dass es dem System von Racket vorausgeht. Allerdings (und das ist wieder ein "IIRC") denke ich, dass das Vertragssystem von Racket das erste System war, das Aufträge höherer Ordnung einführte. Insbesondere, wenn Sie mit Funktionen höherer Ordnung arbeiten, wird das Zuweisen der richtigen Schuld ein wenig komplizierter - zum Beispiel, wenn Sie eine foo
-Funktion nehmen, die einen Vertrag von X? -> Y?
hat, und Sie senden einen Wert, der nicht mit% übereinstimmt. co_de% wird dann der Client-Code verantwortlich gemacht, der diesen Wert an X?
gesendet hat. Aber wenn Ihre Funktion foo
ist und das Prädikat (X? -> Y?) -> Z?
nicht erfüllt ist, dann geht die Schuld an X?
selbst, nicht an den Kunden (und wenn foo
nicht erfüllt ist, liegt die Schuld noch beim Kunden) .
Ich denke, Sie fragen, wie könnte ein Vertragssystem ohne OOP und Vererbung funktionieren? Als ein Benutzer von Racket, der mit Eiffel nicht vertraut ist, frage ich mich, warum ein Vertragssystem etwas mit OOP und Vererbung zu tun haben würde. :)
Auf praktischer Ebene denke ich an Racket-Verträge, um die Vorteile statischer Typdeklarationen zu nutzen und gleichzeitig die Flexibilität dynamisch typisierter Sprachen beizubehalten. Plus-Verträge gehen über nur Typen hinaus und können die Rolle von Behauptungen ausfüllen.
Zum Beispiel kann ich sagen, dass eine Funktion ein Argument benötigt, das eine exakte Ganzzahl ist ... aber auch, dass es eine exakte positive ganze Zahl oder eine Vereinigung bestimmter bestimmter Werte oder in sein soll Tatsache ist jeder beliebig komplizierte Test des übergebenen Wertes. Auf diese Weise kombinieren Verträge in Racket, was Sie mit (a) Typdeklarationen und (b) Behauptungen in zB C / C ++ tun können.
Man kann sich mit Kontrakten in Racket so gut auskennen, dass sie langsam sein können. Ein Weg, um damit fertig zu werden, besteht darin, sie während der Entwicklung zuerst zu verwenden und sie dann selektiv zu entfernen, insbesondere von "inneren Schleifen" -Funktionstypen. Ein weiterer Ansatz, den ich ausprobiert habe, ist es, sie im Groß- / Kleinhandel zu aktivieren: Machen Sie ein paar Module wie contracts-on.rkt und contract-off.rkt, wobei Letzteres Makros zur Verfügung stellt. Benötigen Sie für Ihre Module eine contracts.rkt, die alle aus den Dateien on- oder off bereitstellt. Das ist wie im DEBUG vs RELEASE Modus zu kompilieren.
Wenn du von Eiffel kommst, ist vielleicht meine C / C ++ Orientierung bei Racket-Verträgen nicht hilfreich, aber ich wollte sie trotzdem teilen.
Tags und Links scheme racket eiffel design-by-contract