Normaler ML

Standard ML (SML) ist eine, funktionelle Mehrzweckmodulprogrammiersprache mit der Übersetzungszeit-Datentypprüfung und Typ-Schlussfolgerung. Es ist unter Bearbeiter-Schriftstellern und Programmiersprache-Forschern, sowie in der Entwicklung des Lehrsatzes provers populär.

SML ist ein moderner Nachkomme der ML Programmiersprache, die in der Logik für Berechenbare Funktionen (LCF) Lehrsatz beweisendes Projekt verwendet ist. Es ist unter weit verwendeten Sprachen kennzeichnend, auf denen es eine formelle Spezifizierung hat, die als das Schreiben von Regeln und betrieblicher Semantik in Der Definition von Standard ML (1990 gegeben ist, revidiert und vereinfacht als Die Definition von Standard ML (Revidiert) 1997).

Sprache

Normaler ML ist eine funktionelle Programmiersprache mit einigen unreinen Eigenschaften. In Normalem ML geschriebene Programme bestehen aus Ausdrücken, die, im Vergleich mit Behauptungen oder Befehlen zu bewerten sind, obwohl einige Ausdrücke einen trivialen "Einheits"-Wert zurückgeben und nur für ihre Nebenwirkungen bewertet werden.

Wie alle funktionellen Programmiersprachen ist ein Hauptmerkmal von Normalem ML die Funktion, die für die Abstraktion verwendet wird. Zum Beispiel kann die Factorial-Funktion als ausgedrückt werden:

Spaß factorial n =

wenn n = 0 dann 1 sonst n * factorial (n-1)

Ein ML Standardbearbeiter ist erforderlich, den statischen Typ dieser Funktion ohne benutzergelieferte Typ-Anmerkungen abzuleiten. D. h. es muss ableiten, dass n nur mit Ausdrücken der ganzen Zahl verwendet wird, und deshalb selbst eine ganze Zahl sein muss, und dass alle werterzeugenden Ausdrücke innerhalb der Funktion ganze Zahlen zurückgeben.

Dieselbe Funktion kann mit Clausal-Funktionsdefinitionen ausgedrückt werden, wo, "wenn dann sonst" bedingt durch eine Folge von Schablonen der Factorial-Funktion ersetzt wird, die für spezifische Werte bewertet ist, die durch '|' getrennt sind, die eins nach dem anderen in der schriftlichen Ordnung versucht werden, bis ein Match gefunden wird:

Spaß factorial 0 = 1

| factorial n = n * factorial (n - 1)

Das kann mit einer Fall-Behauptung wie das umgeschrieben werden:

val rec factorial =

fn n => Fall n 0 => 1

| n => n * factorial (n - 1)

oder als eine Lambda-Funktion:

val rec factorial = fn 0 => 1 | n => n * factorial (n-1)

Hier führt das Schlüsselwort eine Schwergängigkeit eines Bezeichners zu einem Wert ein, führt die Definition einer anonymen Funktion ein, und führt eine Folge von Mustern und entsprechenden Ausdrücken ein.

Mit einer lokalen Funktion kann diese Funktion in einem effizienteren Schwanz rekursiver Stil umgeschrieben werden.

Spaß factorial n = hat gelassen

lustige LP (0, acc) = acc

| LP (M, acc) = LP (m-1, m*acc)

in

LP (n, 1)

Ende

(Der Wert eines lassen Ausdrucks ist der des Ausdrucks zwischen in und Ende.) Ist der encapsulation einer invariant-bewahrenden mit dem Schwanz rekursiven dichten Schleife mit einem oder mehr Akkumulator-Rahmen innerhalb einer invariant-freien Außenfunktion, wie gesehen, hier, ein allgemeines Idiom in Normalem ML, und erscheint mit der großen Frequenz im SML-Code.

Typ-Synonyme

Ein Typ-Synonym wird mit dem Typ-Schlüsselwort definiert. Hier ist ein Typ-Synonym für Punkte im Flugzeug und Funktionen, die Entfernungen zwischen zwei Punkten und das Gebiet eines Dreiecks mit den gegebenen Ecken laut der Formel des Reihers schätzend.

lokale

Typ-Nummer = echt * echter

Spaß dist ((x0, y0), (x1, y1)) = hat gelassen

val dx = x1 - x0

val dy = y1 - y0

in

Math.sqrt (dx * dx + dy * dy)

Ende

lustiger Reiher (a, b, c) = hat gelassen

val ab = dist (a, b)

val bc = dist (b, c)

val ac = dist (a, c)

val perim = ab + bc + ac

val s = perim / 2.0

in

Math.sqrt (s * (s - ab) * (s - bc) * (s - ac))

Ende

Algebraischer datatypes und das Muster-Zusammenbringen

Normaler ML stellt starke Unterstützung für algebraischen datatypes zur Verfügung. Von einem ML datatype kann als eine zusammenhanglose Vereinigung gedacht werden. Sie sind leicht zu definieren und leicht zum Programm mit, im großen Teil wegen des Muster-Zusammenbringens von normalem ML sowie der Muster-Erschöpfendkeitsüberprüfung von am meisten normalen ML Durchführungen und Muster-Überfülle-Überprüfung.

Ein datatype wird mit dem datatype Schlüsselwort, als in definiert

datatype gestalten

= Kreis der lokalen Nummer * echt (* Zentrum und Radius *)

| Quadrat der lokalen Nummer * echt (* ober verlassen Ecke und Seitenlänge; Achse-ausgerichtet *)

| Dreieck der lokalen Nummer * lokale Nummer * lokale Nummer (* Ecken *)

(Sieh oben für die Definition dessen.) Zeichen: Datatypes, nicht Typ-Synonyme, sind notwendig, um rekursive Konstrukteure zu definieren. (Das ist im gegenwärtigen Beispiel nicht strittig.)

Ordnungssachen im Muster, das zusammenpasst; Muster, die textlich erst sind, werden zuerst versucht. Muster, das zusammenpasst, kann in Funktionsdefinitionen wie folgt syntaktisch eingebettet werden:

lustiges Gebiet (Kreis (_, r)) = 3.14 * r * r

| Gebiet (Quadrat (_, s)) = s * s

| Gebiet (Dreieck (a, b, c)) = Reiher (a, b, c) (* sieh oben *)

Bemerken Sie, dass Teilelemente, deren Werte in einer besonderen Berechnung nicht erforderlich sind, ellided damit sind, unterstreicht oder so genannte Wildcard-Muster.

Die so genannten "clausal bilden" Stil-Funktionsdefinition, wo Muster sofort nach dem Funktionsnamen erscheinen, ist bloß syntaktischer Zucker für

lustige Bereichsgestalt =

Fall-Gestalt

des Kreises (_, r) => 3.14 * r * r

| Quadrat (_, s) => s * s

| Dreieck (a, b, c) => Reiher (a, b, c)

Muster-Erschöpfendkeitsüberprüfung wird sicherstellen, dass jeder Fall des datatype verantwortlich gewesen worden ist, und eine Warnung erzeugen wird wenn nicht. Das folgende Muster ist inexhaustive:

lustiges Zentrum (Kreis (c, _)) = c

| Zentrum (Quadrat ((x, y), s)) = (x + s / 2.0, y + s / 2.0)

Es gibt kein Muster für den Fall in der Funktion. Der Bearbeiter wird eine Warnung ausgeben, dass das Muster inexhaustive ist, und wenn, an der Durchlaufzeit, passiert zu dieser Funktion zu sein, die Ausnahme erhoben wird.

Der Satz von Klauseln in der folgenden Funktionsdefinition ist erschöpfend und nicht überflüssig:

Spaß hasCorners (Kreis _) = falscher

| hasCorners _ = wahrer

Wenn Kontrolle vorbei am ersten Muster kommt, wissen wir, dass der Wert entweder a oder a sein muss. In jedem jener Fälle wissen wir, dass die Gestalt Ecken hat, so können wir zurückkehren ohne zu unterscheiden, in welchem Fall wir sind.

Das Muster in der zweiten Klausel die folgende (sinnlose) Funktion ist überflüssig:

Spaß f (Kreis ((x, y), r)) = x+y

| f (Kreis _) = 1.0

| f _ = 0.0

Jeder Wert, der das Muster in der zweiten Klausel vergleicht, wird auch das Muster in der ersten Klausel vergleichen, so ist die zweite Klausel unerreichbar. Deshalb stellt diese Definition als Ganzes Überfülle aus, und verursacht eine Übersetzungszeit warnend.

C Programmierer wird häufig markierte Vereinigungen verwenden, auf Anhängsel-Werten entsendend, um zu vollbringen, was ML mit datatypes und dem Muster-Zusammenbringen vollbringt. Dennoch, während ein C mit passenden Kontrollen geschmücktes Programm gewissermaßen so robust sein wird wie das entsprechende ML Programm, werden jene Kontrollen notwendig dynamisch sein; ML stellt eine Reihe statischer Kontrollen zur Verfügung, die dem Programmierer einen hohen Grad des Vertrauens zur Genauigkeit des Programms während der Übersetzung geben.

Bemerken Sie, dass auf objektorientierten Programmiersprachen, wie Java, eine zusammenhanglose Vereinigung ausgedrückt werden kann, indem sie Klassenhierarchien entwirft.

Höherwertige Funktionen

Funktionen können Funktionen als Argumente verbrauchen:

Spaß applyToBoth f x y = (f x, f y)

Funktionen können Funktionen als Rückwerte erzeugen:

Spaß constantFn k = hat gelassen

Spaß const irgendetwas = k

in

const

Ende

(wechselweise)

Spaß constantFn k = (fn irgendetwas => k)

Funktionen können auch beide verbrauchen und Funktionen erzeugen:

Spaß dichtet (f, g) = lassen

Spaß h x = f (g x)

in

h

Ende(wechselweise)

Spaß dichtet (f, g) = (fn x => f (g x))

Die Funktion von der Basisbibliothek ist eine der meistens verwendeten höherwertigen Funktionen in Normalem ML:

lustige Karte _ [] = []

| Karte f (x:: xs) = f x:: Karte f xs

(Eine effizientere Durchführung dessen würde eine mit dem Schwanz rekursive innere Schleife wie folgt definieren:)

lustige Karte f xs = hat gelassen

lustige M ([], acc) = List.rev acc

| M (x:: xs, acc) = M (xs, f x:: acc)

in

M (xs, [])

Ende

Ausnahmen

Ausnahmen werden mit dem Schlüsselwort erhoben, und mit dem Muster behandelt, das Konstruktionen vergleicht.

Ausnahme Unbestimmter

Spaß max [x] = x

| max (x:: Xs) = lassen val M = max xs in wenn x> M dann x sonst M Ende

| max [] = erheben Unbestimmten

lustige wichtige xs = lassen

val msg = (Int.toString (max xs)) behandeln Unbestimmt => "leere Liste... gibt es keinen max!"

in

Druck (msg ^ "\n")

Ende

Das Ausnahme-System kann ausgenutzt werden, um nichtlokalen Ausgang, eine Optimierungstechnik durchzuführen, die für Funktionen wie das folgende passend ist.

Ausnahme-Null

Spaß listProd ns = hat gelassen

Spaß p [] = 1

| p (0:: _) = erheben Null

| p (h:: t) = h * p t

in

(p ns) behandeln Null => 0

Ende

Wenn die Ausnahme im 0 Fall erhoben wird, verlässt Kontrolle die Funktion zusammen. Denken Sie die Alternative: Der Wert 0 würde in den neusten Erwarten-Rahmen zurückgegeben, er würde mit dem lokalen Wert dessen multipliziert, der resultierende Wert (unvermeidlich 0) würde der Reihe nach in den folgenden Erwarten-Rahmen und so weiter zurückgegeben. Die Aufhebung der Ausnahme erlaubt Kontrolle dem Bockspringen direkt über die komplette Kette von Rahmen, und vermeiden Sie die verbundene Berechnung.

Modul-System

Normaler ML hat ein fortgeschrittenes Modul-System, Programmen erlaubend, in hierarchisch organisierte Strukturen des logisch zusammenhängenden Typs und der Werterklärungen zersetzt zu werden. SML Module stellen nicht nur namespace Kontrolle sondern auch Abstraktion im Sinn zur Verfügung, dass sie Programmierern erlauben, abstrakte Datentypen zu definieren.

Drei syntaktische Hauptkonstruktionen umfassen das SML Modul-System: Unterschriften, Strukturen und functors. Eine Struktur ist ein Modul; es besteht aus einer Sammlung von Typen, Ausnahmen, Werten und Strukturen (genannt Unterbauten) paketiert zusammen in eine logische Einheit. Eine Unterschrift ist eine Schnittstelle, gewöhnlich Gedanke als ein Typ für eine Struktur: Es gibt die Namen aller Entitäten an, die durch die Struktur sowie den arities von Typ-Bestandteilen, die Typen von Wertbestandteilen und Unterschriften für Unterbauten zur Verfügung gestellt sind. Die Definitionen von Typ-Bestandteilen können oder dürfen nicht exportiert werden; Typ-Bestandteile, deren Definitionen verborgen werden, sind abstrakte Typen. Schließlich ist ein functor eine Funktion von Strukturen bis Strukturen; d. h. ein functor akzeptiert ein oder mehr Argumente, die gewöhnlich Strukturen einer gegebenen Unterschrift sind, und eine Struktur als sein Ergebnis erzeugt. Functors werden verwendet, um allgemeine Datenstrukturen und Algorithmen durchzuführen.

Zum Beispiel könnte die Unterschrift für eine Warteschlange-Datenstruktur sein:

Unterschrift-WARTESCHLANGE =

sig

Typ 'eine Warteschlange

Ausnahme-Warteschlange

leerer val: 'eine Warteschlange

val isEmpty: 'eine Warteschlange-> bool

Val-Singleton: '-> 'eine Warteschlange

Val-Einsatz: '* 'eine Warteschlange-> 'eine Warteschlange

Val-Piepsen: 'eine Warteschlange-> 'ein

val ziehen um: 'eine Warteschlange-> '* 'eine Warteschlange

Ende

Diese Unterschrift beschreibt ein Modul, das einen parametrisierten Typ von Warteschlangen, eine Ausnahme genannt, und sechs Werte zur Verfügung stellt (von denen fünf Funktionen sind), Versorgung der grundlegenden Operationen auf Warteschlangen. Man kann jetzt die Warteschlange-Datenstruktur durchführen, indem man eine Struktur mit dieser Unterschrift schreibt:

Struktur TwoListQueue:> WARTESCHLANGE =

struct

Typ 'eine Warteschlange = 'eine Liste * 'eine Liste

Ausnahme-Warteschlange

val leer = ([], [])

Spaß isEmpty ([], []) = wahrer

| isEmpty _ = falscher

lustiger Singleton = ([])

lustiger Einsatz (a, (ins, outs)) = (a:: ins, outs)

lustiges Piepsen ([], []) = erziehen Warteschlange

| Piepsen (ins, []) = hd (Umdrehung ins)

| Piepsen (ins, a:: outs) = ein

Spaß zieht um ([], []) = erziehen Warteschlange

| ziehen Sie (ins, []) = um

lassen Sie val newouts = Umdrehung ins

in (hd newouts, ([], tl newouts))

Ende

| ziehen Sie um (ins, a:: outs) = (a, (ins, outs))

Ende

Diese Definition erklärt, dass das eine Durchführung der Unterschrift ist. Außerdem stellt die undurchsichtige Anrechnung (angezeigt durch) fest, dass irgendwelche Typ-Bestandteile, deren Definitionen in der Unterschrift nicht zur Verfügung gestellt werden (d. h.,) als Auszug behandelt werden sollten, bedeutend, dass die Definition einer Warteschlange als ein Paar von Listen außerhalb des Moduls nicht sichtbar ist. Der Körper der Struktur stellt bindings für alle in der Unterschrift verzeichneten Bestandteile zur Verfügung.

Um eine Struktur zu verwenden, kann man auf seinen Typ zugreifen und Mitglieder schätzen, die "Punktnotation" verwenden. Zum Beispiel würde eine Warteschlange von Schnuren Typ haben, die leere Warteschlange ist, und das erste Element von einer Warteschlange zu entfernen, hat gerufen man würde schreiben.

Ein populärer Algorithmus für die Breite das erste Traversal von Bäumen macht Gebrauch von Warteschlangen. Hier präsentieren wir eine Version dieses über eine abstrakte Warteschlange-Struktur parametrisierten Algorithmus:

functor BFT (Q: WARTESCHLANGE) = (* nach Okasaki, ICFP, 2000 *)

struct

datatype 'ein Baum

= E

| T '* 'ein Baum * 'ein Baum

Spaß bftQ (q: 'ein Baum Q.queue): 'eine Liste =

wenn Q.isEmpty q dann []

lassen Sie sonst

val (t, q') = Q.remove q

im Falle dass t

E => bftQ q'

| T (x, l, r) => lassen

val q

in

x:: bftQ q

Ende

Ende

Spaß bft t = bftQ (Q.singleton t)

Ende

Bemerken Sie bitte, dass innerhalb der Struktur das Programm keinen Zugang zur besonderen Warteschlange-Darstellung im Spiel hat. Konkreter gibt es keinen Weg für das Programm dazu, sagen. wählen Sie die erste Liste in der Zwei-Listen-Warteschlange-Darstellung aus, wenn das tatsächlich die Darstellung ist, die wird verwendet. Dieser Datenabstraktionsmechanismus lässt die Breite zuerst aufrichtig agnostisch zur Warteschlange-Darstellungswahl codieren.

Das ist im Allgemeinen wünschenswert; im vorliegenden Fall kann die Warteschlange-Struktur einigen der verschiedenen logischen invariants sicher aufrechterhalten, von denen seine Genauigkeit hinter der kugelsicheren Wand der Abstraktion abhängt.

Codebeispiele

Schnipsel des SML-Codes werden durch das Eingehen in sie in einen "auf höchster Ebene", auch bekannt als eine read-eval-print Schleife am leichtesten studiert. Das ist eine interaktive Sitzung, die die abgeleiteten Typen des Resultierens oder der definierten Ausdrücke druckt. Viele SML Durchführungen stellen einen interaktiven auf höchster Ebene einschließlich SML/NJ zur Verfügung:

$ sml

Normaler ML New Jerseys v110.52 [gebaut: Freitag Jan 21 16:42:10 Uhr 2005]

-

In

Code kann dann an "-" schnell eingegangen werden. Zum Beispiel, um 1+2*3 zu rechnen:

- 1 + 2 * 3;

val es = 7: interne Nummer

Das auf höchster Ebene leitet den Typ des Ausdrucks ab, "um interne Nummer" zu sein, und gibt das Ergebnis "7".

Hallo Welt

Das folgende Programm "hello.sml":

drucken Sie "Hallo Welt! \n";

kann mit MLton kompiliert werden:

$ mlton hello.sml

und durchgeführt:

. $/hallo

Hallo Welt!

Einfügungssorte

Die Einfügungssorte für Listen von ganzen Zahlen (das Steigen) wird kurz wie folgt ausgedrückt:

Spaß ins (n, []) = [n]

| ins (n, ns als h:: t) = wenn (n für diesen Maschinenbediener.

lustige ins' sind.

Mergesort

Hier wird der klassische mergesort Algorithmus in drei Funktionen durchgeführt: Spalt, Verflechtung und mergesort.

Die Funktion wird mit einer lokalen genannten Funktion durchgeführt, der zwei zusätzliche Rahmen hat. Die lokale Funktion wird in einem mit dem Schwanz rekursiven Stil geschrieben; als solcher kann es effizient kompiliert werden. Diese Funktion macht vom Muster von SML Gebrauch, das Syntax vergleicht, um zwischen nichtleerer Liste und leerer Liste Fälle zu unterscheiden. Für die Stabilität wird die Eingangsliste umgekehrt, bevor zu ihr passiert wird.

(* Spalt-Liste in zwei nahe Hälften, zurückgegeben als ein Paar.

* werden Die "Hälften" entweder dieselbe Größe, sein

* oder das erste wird ein mehr Element haben als das zweite.

* Läufe in O (n) Zeit, wo n = xs. *)

lokaler

lustige Schleife (x:: y:: zs, xs, ys) = Schleife (zs, x:: xs, y:: ys)

| Schleife (x:: [], xs, ys) = (x:: xs, ys)

| Schleife ([], xs, ys) = (xs, ys)

in

Spaß hat ns = Schleife (List.rev ns, [], []) gespalten

Ende

Die am Ende lokale Syntax konnte durch eine am Ende gelassene Syntax ersetzt werden, die gleichwertige Definition nachgebend:

Spaß hat sich aufgespalten ns = lassen

lustige Schleife (x:: y:: zs, xs, ys) = Schleife (zs, x:: xs, y:: ys)

| Schleife (x:: [], xs, ys) = (x:: xs, ys)

| Schleife ([], xs, ys) = (xs, ys)

in

Schleife (List.rev ns, [], [])

Ende

Als mit dem Spalt verwendet Verflechtung auch eine lokale Funktionsschleife für die Leistungsfähigkeit. Das innere wird in Bezug auf Fälle definiert: Wenn zwei nichtleere Listen passiert werden, wenn eine nichtleere Liste passiert wird, und wenn zwei leere Listen passiert werden. Bemerken Sie den Gebrauch des Unterstreichens als ein Wildcard-Muster.

Diese Funktion verschmilzt zwei "steigende" Listen in eine steigende Liste. Bemerken Sie, wie der Akkumulator "umgekehrt" gebaut, dann damit umgekehrt wird, bevor er zurückgegeben wird. Das ist eine allgemeine Technik — bauen eine Liste umgekehrt, kehren es dann vor dem Zurückbringen davon um. In SML werden Listen als imbalanced binäre Bäume vertreten, und so ist es zu prepend ein Element zu einer Liste effizient, aber ineffizient, um ein Element an einer Liste anzuhängen. Der Extrapass über die Liste ist eine geradlinige Zeitoperation so, während diese Technik verlangt, dass mehr Wand Zeit zeigt, sind die asymptotics etwas nicht schlechter.

(* Verflechtung zwei geordnete Listen mit dem Ordnungsleutnant

* Pre: Die gegebenen Listen xs und ys müssen bereits pro Leutnant bestellt werden

* Läufe in O (n) Zeit, wo n = xs + ys. *)

lustiger Verflechtungsleutnant (xs, ys) = hat gelassen

lustige Schleife (verlassen als x:: xs, Recht als y:: ys) =

wenn Leutnant (x, y) dann Schleife (x:: xs, Recht)

sonst Schleife (y:: link, ys)

| Schleife (x:: xs, []) = Schleife (x:: xs, [])

| Schleife ([], y:: ys) = Schleife (y:: [], ys)

| Schleife ([], []) = List.rev

in

Schleife ([], xs, ys)

Ende

Die Hauptfunktion.

(* Sortieren eine Liste in gemäß dem gegebenen Befehlen des Operationsleutnants

* Läufe in O (n loggen n), Zeit, wo n = xs.

*)

Spaß mergesort Leutnant xs = hat gelassen

Val-Verflechtung' = verschmilzt Leutnant

lustige Millisekunde [] = []

| Millisekunde [x] = [x]

| Millisekunden xs = lassen

val (verlassen, Recht) = spalten xs

in

verschmelzen Sie sich' (Millisekunde, ist Millisekunde-Recht abgereist)

Ende

in

Millisekunde xs

Ende

Bemerken Sie auch, dass der Code keine Erwähnung von variablen Typen, mit Ausnahme von macht:: Und [] Syntax, die Listen bedeuten. Dieser Code wird Listen jedes Typs sortieren, so lange ein konsequenter Einrichtungsfunktionsleutnant definiert werden kann. Mit der Typ-Schlussfolgerung von Hindley-Milner ist der Bearbeiter dazu fähig, die Typen aller Variablen, sogar komplizierte Typen wie die der Leutnant-Funktion abzuleiten.

Schnellsortierung

Schnellsortierung kann wie folgt ausgedrückt werden. Diese allgemeine Schnellsortierung verbraucht einen Ordnungsmaschinenbediener.

val filt = List.filter

lustige Schnellsortierung

sonst, wenn typeOf e2

sonst typeOf e2

Spaß eval (Wahr) = Wahrer

| eval (Falsch) = Falscher

| eval (Interne Nummer n) = Interne Nummer n

| eval (Nicht e) =

(Fall eval e

Wahrer => Falscher

| Falsch => Wahrer

| _ => erheben Fehlen "Datentypprüfung wird" gebrochen)

| eval (Tragen (e1, e2)) Bei, = lassen

val (Interne Nummer n1) = eval e1

val (Interne Nummer n2) = eval e2

in

Interne Nummer (n1 + n2)

Ende

| eval (Wenn (e1, e2, e3)) =

wenn eval e1 = Wahr dann eval e2 sonst eval e3

Spaß chkEval e = (ignorieren (typeOf e); eval e) (* wird erheben, Irren Sich auf dem Typ-Fehler *)

Willkürliche Präzision factorial Funktion (Bibliotheken)

In SML stellt das Modul von IntInf Arithmetik der ganzen Zahl der willkürlichen Präzision zur Verfügung. Außerdem können Druckfehler der ganzen Zahl als ganze Zahlen der willkürlichen Präzision ohne den Programmierer verwendet werden, der irgendetwas tun muss.

Das folgende Programm "fact.sml" führt eine willkürliche Präzision factorial Funktion durch und druckt den factorial 120:

lustige Tatsache n: IntInf.int =

wenn n=0 dann 1 sonst n * Tatsache (n - 1)

val =

Druck (IntInf.toString (Tatsache 120) ^ "\n")

und kann kompiliert und geführt werden mit:

$ mlton fact.sml

$./Tatsache

66895029134491270575881180540903725867527463331380298102956713523016335 57244962989366874165271984981308157637893214090552534408589408121859898 481114389650005964960521256960000000000000000000000000000

Numerische Ableitung (höherwertige Funktionen)

Da SML eine funktionelle Programmiersprache ist, ist es leicht, Funktionen in SML Programmen zu schaffen und zu verteilen. Diese Fähigkeit hat eine riesige Menge von Anwendungen. Das Rechnen der numerischen Ableitung einer Funktion ist eine solche Anwendung. Die folgende SML-Funktion "d" schätzt die numerische Ableitung einer gegebenen Funktion "f" an einem gegebenen Punkt "x":

- Spaß d Delta f x =

(f (x + Delta) - f (x - Delta)) / (2.0 * Delta);

val d = fn: echt-> (echt-> echt)-> echt-> echter

Diese Funktion verlangt einen kleinen Wert "Delta". Eine gute Wahl für das Delta, wenn sie diesen Algorithmus verwendet, ist die Würfel-Wurzel des Maschinenepsilons.

Der Typ der Funktion "d" zeigt an, dass es eine "Hin- und Herbewegung" auf eine andere Funktion mit dem Typ" (echt-> echt)-> echt-> echt kartografisch darstellt". Das erlaubt uns, Argumente teilweise anzuwenden. Dieser funktionelle Stil ist bekannt als, mit Currysoße zuzubereiten. In diesem Fall ist es nützlich, das erste Argument "Delta" auf "d" teilweise anzuwenden, eine mehr spezialisierte Funktion zu erhalten:

- val d = d 1E~8;

val d = fn: (echt-> echt)-> echt-> echter

Bemerken Sie, dass der abgeleitete Typ anzeigt, dass der Ersatz "d" eine Funktion mit dem Typ "echt-> echt" als sein erstes Argument erwartet. Wir können eine numerische Annäherung an die Ableitung an schätzen mit:

- d (fn x => x * x * x - x - 1.0) 3.0;

val es = 25.9999996644: echter

Die richtige Antwort ist =>.

Die Funktion "d" wird eine "höherwertige Funktion" genannt, weil sie eine andere Funktion ("f") als ein Argument akzeptiert.

Mit Currysoße zubereitete und höherwertige Funktionen können verwendet werden, um überflüssigen Code zu beseitigen. Zum Beispiel kann eine Bibliothek Funktionen des Typs verlangen, aber es ist günstiger, Funktionen des Typs zu schreiben, wo es eine feste Beziehung zwischen den Gegenständen des Typs gibt und. Eine höhere Ordnungsfunktion des Typs (* c-> b)-> (-> kann b) diese Allgemeinheit ausklammern. Das ist ein Beispiel des Adapter-Musters.

Getrennte Elementarwelle verwandelt sich (Muster, das zusammenpasst)

1D verwandelt sich Elementarwelle von Haar von einer Macht der ganzen Zahl von zwei Länge-Liste von Zahlen kann sehr kurz und bündig in SML durchgeführt werden und ist ein ausgezeichnetes Beispiel des Gebrauches des Musters, das über Listen zusammenpasst, Paare von Elementen ("h1" und "h2") von der Vorderseite nehmend und ihre Summen und Unterschiede auf den Listen "s" und "d" beziehungsweise versorgend:

- Spaß haar l = hat gelassen

Spaß aux [s] [] d = s:: d

| aux [] s d = aux s [] d

| aux (h1:: h2:: t) s d = aux t (h1+h2:: s) (h1-h2:: d)

| aux _ _ _ = erheben Leeren

in

aux l [] []

Ende;

val haar = fn: Int Liste-> interne Nummer verzeichnet

Zum Beispiel:

- haar [1, 2, 3, 4, ~4, ~3, ~2, ~1];

val es = [0,20,4,4, ~1, ~1, ~1, ~1]: int Liste

Muster, das zusammenpasst, ist eine nützliche Konstruktion, die komplizierten Transformationen erlaubt, klar und kurz und bündig vertreten zu werden. Außerdem verwandeln SML Bearbeiter Muster-Matchs in den effizienten Code, auf Programme hinauslaufend, die nicht nur kürzer sondern auch schneller sind.

Durchführungen

Viele SML Durchführungen bestehen, einschließlich:

  • MLton ist ein ganzes Programm, Bearbeiter optimierend, der sehr schnellen Code im Vergleich zu anderen ML Durchführungen erzeugt. http://www.mlton.org
  • Poly/ML ist eine volle Durchführung von Normalem ML, der schnellen Code erzeugt und Mehrkernhardware (über Fäden von Posix) unterstützt.
  • Isabelle/ML integriert parallelen Poly/ML in einen interaktiven Lehrsatz prover, mit einem hoch entwickelten IDE (gestützt auf jEdit) sowohl für ML als auch für die Probesprache.
  • Normaler ML New Jerseys (hat SML/NJ abgekürzt), ist ein voller Bearbeiter, mit verbundenen Bibliotheken, Werkzeugen, einer interaktiven Schale und Dokumentation. http://www.smlnj.org /
  • Moskau ML ist eine Leichtgewichtsdurchführung, die auf dem CAML Leichten Laufzeitmotor gestützt ist. Es führt die volle SML Sprache, einschließlich SML Module und viel von der SML Basisbibliothek durch.
http://www.itu.dk/people/sestoft/mosml.html
  • NEIGUNG ist ein voller bezeugender Bearbeiter für SML. Es verwendet getippte Zwischensprachen, um Code zu optimieren und Genauigkeit zu sichern, und kann in die getippte Zusammenbau-Sprache kompilieren.
  • Hamlet ist ein SML Dolmetscher, der zum Ziel hat, eine genaue und zugängliche Bezugsdurchführung des Standards zu sein.
  • Der ML Kit integriert einen Müllmann (der arbeitsunfähig sein kann), und das Gebiet-basierte Speichermanagement mit der automatischen Schlussfolgerung von Gebieten, Echtzeitanwendungen richtend. Seine Durchführung basiert sehr nah auf der Definition.
  • SML.NET erlaubt, zum Microsoft CLR zu kompilieren, und hat Erweiterungen, um sich mit anderem.NET-Code zu verbinden.
  • SML2c ist ein Gruppe-Bearbeiter und kompiliert nur Behauptungen des Modul-Niveaus (d. h. Unterschriften, Strukturen, functors) in C. Es basiert auf der SML/NJ Version 0.67 und teilt das Vorderende und den grössten Teil seines Laufzeitsystems, aber unterstützt das SML/NJ Stil-Beseitigen und Kopierfräs-nicht. Programme des Modul-Niveaus, die auf SML/NJ laufen, können durch sml2c ohne Änderungen kompiliert werden.
  • Das Poplog System führt eine Version von SML, mit dem KNALL 11, und fakultativ Allgemeines Lispeln und Einleitung durch, gemischte Sprachprogrammierung erlaubend. Für alle ist die Durchführungssprache KNALL 11, der zusätzlich kompiliert wird. Es hat auch einen einheitlichen Emacs ähnlichen Redakteur, der mit dem Bearbeiter kommuniziert.
  • SML# ist eine gute Konservativer-Erweiterung der japanischen Qualität von SML, der Aufzeichnung polymorphism und C (nicht C#) Zwischenfunktionsfähigkeit zur Verfügung stellt. Es ist herkömmlicher heimischer Bearbeiter und nicht verbunden mit.NET oder C# vielleicht, aber Name, seien Sie nicht verwirrt.
  • Alice: ein Dolmetscher für Normalen ML durch die Universität von Saarland das Hinzufügen von Eigenschaften für die faule Einschätzung, Parallelität (Nebenläufigkeit und verteilte Computerwissenschaft über entfernte Verfahren-Anrufe) und Einschränkungsprogrammierung.

Alle diese Durchführungen sind offene Quelle und frei verfügbar. Die meisten werden selbst in SML durchgeführt. Es gibt nicht mehr irgendwelche kommerziellen SML Durchführungen. Harlekin hat einmal einen kommerziellen IDE und Bearbeiter für SML genannt MLWorks erzeugt. Die Gesellschaft ist jetzt verstorben. Wie man glaubt, ist MLWorks zu Xanalys verzichtet worden.

Siehe auch

  • Alice
  • ML
  • Gleichzeitiger ML
  • Abhängiger ML
  • Ausziehbarer ML
  • Erweiterter ML
F#

Links


Dhara / Jerry Herman
Impressum & Datenschutz