Standard ML | |
---|---|
Semantik | Formel , fortolkningsorienteret |
Sprog klasse |
anvendelig , funktionel , imperativ |
Udførelsestype | generelle formål |
Dukkede op i | 1984 [1] , 1990 [2] , 1997 [3] |
Forfatter | Robin Milner og andre |
Filtypenavn _ | .sml |
Frigøre | Standard ML '97 (1997 ) |
Type system | Hindley - Milner |
Større implementeringer | mange |
Dialekter | Alice , SML# , Manticore og andre |
Blev påvirket | Lisp , ISWIM , ML , POP-2 , Hope , Clear [4] |
påvirket |
Erlang , OCaml , Haskell , efterfølger ML (sML) |
Licens | åben kildekode |
Internet side | sml-family.org |
Platform |
x86 , AMD64 , PowerPC , ARM , SPARC , S390 , DEC Alpha , MIPS , HPPA , PDP-11 , JVM , .Net , LLVM , C-- , TAL , C [5] , Ada [6] |
OS |
* BSD , Linux ( Debian , Fedora , osv.) , Windows , Cygwin , MinGW , Darwin , Solaris , Hurd , AIX , HP-UX |
Standard ML ( SML er et overordnet kompileret programmeringssprog til generelle formålbaseret på Hindley-Milner-systemet .
Det er kendetegnet ved en matematisk præcis definition (som garanterer identiteten af programmernes betydning uanset compiler og hardware), som har en dokumenteret pålidelighed af statisk og dynamisk semantik. Det er et "for det meste funktionelt " sprog [7] [8] , det vil sige, at det understøtter de fleste af de tekniske funktioner i funktionelle sprog, men giver også avancerede imperative programmeringsmuligheder , når det er nødvendigt. Kombinerer stabilitet af programmer, fleksibilitet på niveau med dynamisk indtastede sprog og hastighed på niveau med C -sprog ; giver fremragende support til både hurtig prototyping og modularitet og programmering i stor skala [9] [10] .
SML var det første selvstændige kompilerede sprog i ML -familien og fungerer stadig som ankersproget i ML -udviklingsfællesskabet ( efterfølger ML ) [11] . SML var den første til at implementere et unikt applikativt modulsystem , ML-modulsproget .
Sproget er oprindeligt fokuseret på storskala programmering af softwaresystemer: det giver effektive midler til abstraktion og modularitet , hvilket giver en høj kodegenbrugshastighed , og dette gør det også velegnet til hurtig prototyping af programmer, herunder storskala . For eksempel, under udviklingen af den (dengang stadig eksperimentelle) SML/NJ-kompiler ( 60 tusind linjer pr. SML), var det nogle gange nødvendigt at foretage radikale ændringer i implementeringen af nøgledatastrukturer, der påvirker snesevis af moduler - og den nye version af compileren blev klar i løbet af dagen. [9] (Se også ICFP Programming Contest 2008, 2009.) Men i modsætning til mange andre sprog, der er egnede til hurtig prototyping , kan SML kompilere meget effektivt .
SML er kendt for sin relativt lave adgangstærskel og fungerer som undervisningssprog i programmering på mange universiteter rundt om i verden [12] . Det er omfattende dokumenteret i arbejdsform og bruges aktivt af videnskabsmænd som grundlag for at forske i nye elementer i programmeringssprog og idiomer (se f.eks. polymorfi af strukturelle typer ). På nuværende tidspunkt er alle implementeringer af sproget (inklusive forældede) blevet open source og gratis .
Sproget har en matematisk præcis ( eng. rigorous ) formel definition kaldet "Definition" ( eng. The Definition ). Til definitionen er der bygget en fuld type sikkerhedsbevis , som garanterer stabiliteten af programmer og forudsigelig adfærd selv med forkerte inputdata og mulige programmeringsfejl. Selv et buggy SML-program opfører sig altid som et ML-program: det kan gå i beregning for evigt eller kaste en undtagelse , men det kan ikke gå ned [13] .
SML er et for det meste funktionelt ( for det meste funktionelt eller primært funktionelt ) sprog [7] [8] , det vil sige, at det understøtter de fleste af de tekniske funktioner i funktionelle sprog, men giver også imperative programmeringsmuligheder . Det er mere almindeligt omtalt som et " højere ordens sprog for at understrege støtte til førsteklasses funktioner, mens det stadig adskiller det fra referentielt gennemsigtige sprog .
SML giver enestående support til programmering i stor skala gennem det mest kraftfulde og udtryksfulde modulsystem kendt ( ML Module Language ). SML implementerer en tidlig version af modulsproget, som er et separat lag af sproget: moduler kan indeholde kernesprogobjekter, men ikke omvendt [14] .
I modsætning til mange andre sprog i ML -familien ( OCaml , Haskell , F# , Felix, Opa, Nemerle og andre), er SML meget minimalistisk: det har ikke indfødt objektorienteret programmering , samtidighed , ad-hoc polymorfi , dynamisk skrivning , listegeneratorer og mange andre funktioner. SML er dog ortogonal [15] (det vil sige, at den implementerer det mindst nødvendige, men det fulde sæt af maksimalt forskellige elementer), hvilket gør det relativt nemt at efterligne andre funktioner, og de nødvendige teknikker er dækket bredt i litteraturen . Faktisk giver SML dig mulighed for at bruge vilkårlig funktionalitet på højt niveau som en primitiv til at implementere funktionalitet på endnu højere niveau [16] . Især er implementeringsmodeller af typeklasser og monader bygget ved hjælp af kun standard SML-konstruktioner, samt objektorienterede programmeringsværktøjer [17] . Desuden er SML et af de få sprog, der direkte implementerer førsteklasses fortsættelser .
Hindley-Milner (X-M)-systemet er et karakteristisk træk ved ML og dets efterkommere. Det sikrer programmernes pålidelighed på grund af tidlig detektering af fejl, høj kodegenbrug , høj potentiale for optimering , kombinerer disse kvaliteter med kortfattethed og udtryksfuldhed på niveauet af dynamisk indtastede sprog. De mest fremtrædende egenskaber, der er iboende i X-M, er type polymorfi , såvel som algebraiske datatyper og mønstermatchning på dem.
Implementeringen af X-M i SML har følgende funktioner:
I modsætning til mange sprog giver SML en lang række måder at bruge det på [21] :
På samme tid, i visse tilstande, er en række forskellige målplatforme og kompileringsstrategier mulige :
Selve kompileringsstrategierne adskiller sig også væsentligt:
Værdibegrænsning _ _ _ _
KontrolstrukturerModularitet
SML - modulsystemet er det mest udviklede modulsystem inden for programmeringssprog. Det gentager semantikken i kerne-ML ( eng. Core ML ), således at afhængigheder mellem store programkomponenter bygges som afhængigheder på et lille niveau. Dette system af moduler består af tre typer moduler:
Strukturer ligner moduler i de fleste programmeringssprog. Signaturer tjener som strukturgrænseflader, men er ikke stift bundet til bestemte strukturer, men bygger relationer i henhold til " mange-til-mange " -skemaet , hvilket giver dig mulighed for fleksibelt at kontrollere synligheden af strukturkomponenter afhængigt af behovene i programkonteksten.
Funktioner er " funktioner over strukturer ", som giver dig mulighed for at bryde kompileringstidsafhængigheder og beskrive parameteriserede moduler. De gør det muligt at skrive -sikkert beskrive beregninger på programkomponenter, der på andre sprog kun kan implementeres gennem metaprogrammering [23] - som C++ skabeloner , kun uden smerte og lidelse [24] , eller Lisp makrosproget , kun med statisk sikkerhedskontrol af den genererede kode [23] . De fleste sprog har slet ikke noget, der kan sammenlignes med funktioner [25] .
Den grundlæggende forskel mellem ML-modulsproget er, at resultatet af en funktor ikke kun kan indeholde værdier, men også typer, og de kan afhænge af de typer, der er en del af funktorparameteren. Dette gør ML-moduler nærmest i deres udtryksevne til systemer med afhængige typer , men i modsætning til sidstnævnte kan ML-moduler reduceres til et fladt System F ω (se Modulsprog ML#F-Rossberg-Rousseau-Dreyer ).
Sprogets syntaks er meget kort, med hensyn til antallet af reserverede ord indtager det en mellemposition mellem Haskell og Pascal [26] .
SML har en kontekstfri grammatik , selvom der er nogle uklarheder i den. SML/NJ bruger LALR(1) , men LALR(2) findes ét sted.
Liste over sprogsøgeord ( identifikatorer , der matcher dem , er ikke tilladt) [27] :
abstype og og også som case datatype do else end eqtype undtagelse fn fun functor handle if in include infix infixr lad local nonfix of op open orelse raise rec deling signatur struct struktur så skriv val hvor mens med withtypeTegnidentifikatorer er også tilladt - det vil sige, type-, data- og funktionsnavne kan bestå af følgende ikke-alfabetiske tegn:
! % & $ # + - * / : < = > ? @ \ ~ ' ^ |Navnene på disse symboler kan have en hvilken som helst længde [27] :
val ----> = 5 sjovt !!? ©**??!! x = x - 1 infix 5 $^$^$^$ sjov a $^$^$^$ b = a + b val :-|==>-># = Liste . foldrSelvfølgelig er brugen af sådanne navne i praksis ikke ønskelig, men hvis den tidligere forfatter af den vedligeholdte kode brugte dem i vid udstrækning, så bliver det muligt takket være den formelle definition (og SML selv gør det ret nemt at løse dette problem) skrive en præprocessor til at rette hukommelsestegn.
Kun følgende tegnstrenge er udelukket:
: | ==> -> # :>Årsagen til denne begrænsning ligger i deres særlige rolle i sprogets syntaks:
: - eksplicit værditype annotation _ | - adskillelse af prøver = - adskille funktionslegemet fra dets overskrift => - at adskille lambdafunktionens krop fra dens header -> — konstruktør af funktionel (pile) type # - adgang til registreringsfeltet :> - at matche strukturen med signaturenSML har ingen indbygget syntaks for arrays og vektorer (konstante arrays). Nogle implementeringer understøtter til en vis grad syntaksen for arrays ( [|1,2,3|]) og vektorer ( ) #[1,2,3]som en udvidelse.
Opgaveoperationen er skrevet som på Pascal -sprog :x:=5
SML - standardbiblioteket hedder Basis . Det har udviklet sig over mange år efter at have gennemgået strenge tests på reelle problemer baseret på SML/NJ , dets udkast blev offentliggjort i 1996 [28] , og derefter blev dets specifikation officielt offentliggjort i 2004 [29] . I denne periode udkom der allerede manualer til dets brug [30] . Basisbiblioteket implementerer kun det nødvendige minimum af moduler: trivielle datatyper, aritmetik over dem, input-output , platformsuafhængig grænseflade til operativsystemet osv., men implementerer ikke mere kompleks funktionalitet (for eksempel multithreading). Mange compilere giver desuden forskellige eksperimentelle biblioteker.
Kompilere kan bruge viden om Basis til at anvende præ-optimerede algoritmer og specialiserede optimeringsteknikker: MLton bruger f.eks. den native repræsentation af Basis-typer (svarende nøjagtigt til primitive C -sprogtyper ) samt de enkleste aggregerede typer, der består af dem.
Som med de fleste sprog har SML Basis en række specifikke arkitektoniske og syntaktiske konventioner. Først og fremmest er disse trivielle komponenter i standardstrukturer, såsom kombinatorer, der ligner navn og signaturer (såsom fold). Yderligere er dette et skema, der gælder for de fleste typer konvertering til strengtype og omvendt .
Konvertere og scannereStandardskemaet for konvertering til og fra en strengtype er indkapslet i en struct StringCvt:
struktur StringCvt : sig datatype radix = BIN | okt | DEC | HEX datatype realfmt = SCI af int option | FIX af int option | GEN af int option | PRÆCIS type ( 'a , 'b ) reader = 'b -> ( 'a * 'b ) mulighed val padVenstre : char -> int -> streng -> streng val padHøjre : char -> int -> streng -> streng val splitl : ( char -> bool ) -> ( char , 'a ) reader -> 'a -> ( string * ' a ) val takl : ( char -> bool ) -> ( char , ' a ) reader -> ' a -> string val dropl : ( char -> bool ) -> ( char , ' a ) reader - > 'a -> 'a val skipWS : ( char , 'a ) reader -> 'a -> 'a type cs val scanString : (( char , cs ) reader -> ( 'a , cs ) reader ) -> string -> 'a option endKonverteringsskemaet er ikke begrænset til at opstille baser af talsystemer, som i C ( BIN, OCT, DEC, HEX). Det strækker sig til højere ordens programmering , hvilket giver dig mulighed for at beskrive operationerne ved at læse værdier af specifikke typer fra abstrakte strømme og skrive til dem, og derefter transformere simple operationer til mere komplekse ved hjælp af kombinatorer . Streams kan være standard I/O- streams eller blot aggregerede typer såsom lister eller strenge. [31]
Læsere, det vil sige værdier af typen ('a,'b) reader. Intuitivt er en læser en funktion, der tager en strøm af type som input 'bog forsøger at læse en værdi af type fra den 'a, og returnerer enten den læste værdi og "resten" af strømmen, eller NONEhvis den fejler. En vigtig type læsere er scannere eller scanningsfunktioner. For en given type har Tscanningsfunktionen typen
( char , 'b ) læser -> ( T , 'b ) læser- det vil sige, at det er en konverter fra en karakterlæser til en læser af denne type. Scannere er inkluderet i mange standardmoduler, for eksempel INTEGERinkluderer signaturen en scanner for heltal:
signatur INTEGER = sig eqtype int ... val scan : StringCvt . radix -> ( char , 'a ) StringCvt . reader -> 'a -> ( int * 'a ) option endTal læses atomært, men læsere kan læse fra strømme og kæder element for element, for eksempel tegn for tegn en linje fra en streng:
fun stringGetc ( s ) = lad val ss = Understreng . fulde ( r ) i tilfælde af Substring . getc ( ss ) af INGEN => INGEN | SOME ( c , ss' ) => SOME ( c , Understreng . streng ( ss' )) ende ; stringGetc ( "hej" ); (* val it = SOME (#"h","ello") : (char * string) option *) stringGetc ( #2 ( valOf it ) ); (* val it = SOME (#"e","llo") : (char * string) option *) stringGetc ( #2 ( valOf it ) ); (* val it = SOME (#"l","lo") : (char * string) option *) stringGetc ( #2 ( valOf it ) ); (* val it = SOME (#"l","o") : (char * string) option *) stringGetc ( #2 ( valOf it ) ); (* val it = SOME (#"o","") : (char * string) option *) stringGetc ( #2 ( valOf it ) ); (* val it = INGEN : (char * streng) mulighed *)Scannere giver dig mulighed for at oprette læsere fra eksisterende læsere, for eksempel:
val stringGetInt = Int . scan StringCvt . DEC -strengHentStrukturen StringCvtgiver også en række hjælpefunktioner. For eksempel, splitlog takelkombiner dropltegnlæsere med tegnprædikater for at tillade, at streams kan filtreres.
Det skal bemærkes, at ikke karakterlæsere er et særligt tilfælde af læsere generelt, men omvendt [32] . Grunden til dette er, at udtrækning af en undersekvens fra en sekvens er en generalisering af at udtrække en understreng fra en streng.
definitionen ret strengt . Forskellene ligger i tekniske detaljer, såsom det binære format af separat kompilerede moduler, implementeringen af FFI osv. I praksis skal et rigtigt program starte fra et bestemt grundlag (et minimumssæt af typer, input-output faciliteter , etc.). Definitionen stiller dog kun minimale krav til sammensætningen af det oprindelige grundlag, så det eneste observerbare resultat af et korrekt program ifølge definitionen er, at programmet afslutter eller afgiver en undtagelse, og de fleste implementeringer er kompatible på dette niveau [33] .
Selv standarden Basis har dog nogle potentielle problemer med overførsel. For eksempel [33] indeholder en konstant værdien af det størst mulige heltal, pakket ind i den valgfri type , og skal hentes enten ved mønstermatchning eller ved et funktionskald . For finite dimensionstyper er værdien , og begge ekstraktionsmetoder er ækvivalente. Men er lig , så adgang til indholdet direkte via vil give en undtagelse . Åbnet som standard , for eksempel i Poly/ML -kompileren . Int.maxIntvalOfIntN.maxIntSOME(m)IntInf.maxIntNONEvalOf OptionIntInf
Med en vis indsats er det muligt at udvikle programmer, der er frit bærbare mellem alle aktuelle implementeringer af sproget. Et eksempel på et sådant program er HaMLet .
Til dato er Standard ML blevet fuldstændig offentligt: alle implementeringer er gratis og open source og distribueres under de mest loyale licenser ( BSD-stil , MIT ); teksterne til Sprogdefinitionen (både i 1990-versionen og den reviderede 1997-version) og Basisspecifikationen er også tilgængelige gratis .
SML har et stort antal implementeringer. En betydelig del af dem er skrevet i selve SML; undtagelserne er kørselstiderne for nogle kompilatorer skrevet i C og Assembler , såvel som Poplog systemet .
Kompilere til native kode
Verifikation af compilere
Kompilere til bytekoder og Java
Implementeringer på højere niveau
Forældede implementeringer
SML#
SML# [56] udvider konservativt SML med rekordpolymorfi i Atsushi Ohori-modellen , som SML# bruger til problemfrit at indlejre SQL i SML-kode til intensiv databaseprogrammering.
Pundsymbolet ( #) i sprognavnet symboliserer vælgeren (handlingen med at vælge et felt fra en post). Compileren af samme navn hævder god ydeevne. Udviklet og udviklet på Tohoku Institute (Japan) under vejledning af Ohori selv.
AliceAlice ML udvider konservativt SML med primitiver for samtidig programmering baseret på den eksotiske" opkald af fremtidig " evalueringsstrategi , begrænsningsløseren og alle de konsistente elementer i det efterfølgende ML- design . Især Alice understøtter førsteklasses moduler i form af pakker med dynamisk indlæsning og dynamisk typing , som tillader implementering af distribueret computing . Alice giver også futures førsteklasses egenskaber, herunder leverer futures på modulniveau ( fremtidige strukturer og fremtidige signaturer). Compileren bruger en virtuel maskine. Udviklet og udviklet på Saarland University under ledelse af Andreas Rossberg.
Samtidig MLConcurrent ML (CML) et integreret sprogbibliotek, derudvider SML med højere ordens samtidige programmeringskonstruktioner baseret på densynkroneførsteklassesmeddelelsesmodel. Inkluderet i standarddistributionen af SML/NJ ogMLton-kompilatorerne. Kerneideerne i CML er kernen i Manticore -projektet og er indarbejdet i det efterfølgende ML -projekt [11] .
ManticoreManticore [40] implementerer omfattende support til samtidig og parallel programmering, fra den logiske nedbrydning af et system til processer til finkornet kontrol over den mest effektive brug af multi-core systemer . Manticore er baseret på en delmængde af SML, eksklusive mutable arrays og referencer, dvs. det er et rent sprog, der opretholder en streng evalueringsrækkefølge . Eksplicitte samtidigheds- og grove parallelismemekanismer ( tråde ) er baseret på CML , mens fine datalags - parallelismemekanismer (parallelle arrays ) ligner NESL . Compileren af samme navn genererer indbygget kode .
MLPolyRMLPolyR er et legetøjssprog, der er baseret på en simpel delmængde af SML og tilføjer flere niveauer af typesikkerhed til det . Målet med projektet er at uddybe studiet af rekordpolymorfi til behovene i det efterfølgende ML -projekt . Det innovative MLPolyR - system løser -udtryksproblemet og garanterer ingen ubehandlede undtagelser i programmer.
Udviklet under ledelse af Matthias Blum (forfatter af NLFFI ) ved Toyota Institute of Technology i Chicago , USA .
MythrylMythryl [57] er en syntaksvariant af SML, der har til formål at fremskynde POSIX- udviklingen . Den nye syntaks er stærkt lånt fra C; terminologien er også blevet revideret til at være mere traditionel (f.eks. er funktorer blevet omdøbt til generiske ). Samtidig understreger forfatterne, at de ikke har til hensigt at skabe "endnu et dump af sprogtræk", men holder sig til SML's minimalistiske karakter og stoler på dens definition . Implementeringen er en forgrening af SML/NJ .
Andre
Der er ingen krav til design af programmer i SML, da sprogets grammatik er fuldstændig kontekstfri og ikke indeholder åbenlyse uklarheder. Den bemærker dog særlige problemer, for eksempel, når man passerer multiplikationsoperatoren, skal den op *afsluttende parentes adskilles med et mellemrum ( (op * )), da når de skrives i kontinuerlig form, tager mange implementeringer (ikke alle) et par tegn *)for at lukke en kommentar i koden og generere en fejl.
Der er dog stadig visse anbefalinger, der sigter mod at forbedre læsbarheden, modulariteten og genbrug af kode, samt tidlig opdagelse af fejl og øge modificerbarheden (men ikke til at indtaste oplysninger om typer i identifikatorer, som det f.eks. gøres i ungarsk notation ) [ 64] . SML anbefaler især en navnekonvention for kerneniveauidentifikatorer svarende til den, der kræves af Haskell : fooBarfor værdier, foo_barfor typekonstruktører , FooBarfor konstruktørfunktioner (nogle kompilatorer udsender endda en advarsel, hvis den overtrædes). Dette skyldes karakteren af mønstermatching, som generelt ikke er i stand til at skelne mellem lokal variabel input og nul- type konstruktørbrug , så stavefejl kan føre til (relativt let opdagelige) fejl [65] .
Det mest usædvanlige og uventede kan være:
For procedurer anvendes det samme formsprog som i C : procedurer er repræsenteret af funktioner, der returnerer en værdi af en enkelt type :
sjov p s = print s (* val p = fn : sting -> enhed *) Sekventiel databehandling lad D i E ende sjov foo ... = lad val _ = ... i ... endeDette -expansion ( engelsk eta-expansion ) udtrykeer et udtrykfn z => e z, det vil sige en indpakning af det oprindelige udtryk til en lambda-funktion , hvorzdet ikke forekommer ie. Dette giver selvfølgelig kun mening, hvisedet har en piltype , det vil sige, det er en funktion. Denne -udvidelse tvinger evalueringen til at blive forsinket,eindtil funktionen anvendes, og til at blive revurderet, hver gang den anvendes. Denne teknik bruges i SML til at overvinde de ekspressivitetsbegrænsninger, der er forbundet med semantikken værdibegrænsningen . Udtrykket " eta -ekspansion" er lånt fra eta -transformationen i lambda calculus , der tværtimod betyder reduktionen af et udtryktil,hvis detikke forekommer i( eta -kontraktion). [67] [68]fn z => e zeze
Værdier indekseret efter typerVærdier indekseret efter typer ( engelsk typeindekserede værdier ) er en teknik, der giver dig mulighed for at introducere understøttelse af ad-hoc polymorfi i SML (som den i første omgang mangler) [69] . Der er en række af dens varianter, herunder dem, der har til formål at understøtte fuldgyldig objektorienteret programmering [17] .
Fold" Fold " [70] er en teknik, der introducerer en række almindelige idiomer i SML, herunder variadiske funktioner, navngivne funktionsparametre, standardparameterværdier, syntaktisk understøttelse af arrays i kode, funktionel opdatering af poster og en kosmetisk repræsentation af afhængig indtastning at give typesikkerhed af funktioner som printf.
PrincipDet er nødvendigt at definere tre funktioner - fold, step0og $- sådan at følgende lighed er sand:
fold ( a , f ) ( step0 h1 ) ( step0 h2 ) ... ( step0 hn ) $ = f ( hn (... ( h2 ( h1 a ))))Deres minimale definition er lakonisk:
sjov $ ( a , f ) = f a struktur Fold = struktur sjov fold ( a , f ) g = g ( a , f ) sjov step0 h ( a , f ) = fold ( h a , f ) endeEn mere avanceret implementering giver dig mulighed for at kontrollere typerne af udtryk ved hjælp af Fold.
Eksempel: variabelt antal funktionsargumenter val sum = fn z => Fold . fold ( 0 , fn s => s ) z sjov a i = Fold . step0 ( fn s => i + s ) ... sum ( a 1 ) ( a 2 ) ( a 3 ) $ (* val it : int = 6 *)
Eksempel: liste bogstaver val liste = fn z => Fold . fold ([], rev ) z val ' = fn z => Fold . step1 ( op :: ) z ... liste 'w 'x 'y 'z $
Eksempel: (kosmetisk) afhængige typer val f = fn z => Fold . fold ((), id ) z val a = fn z => Fold . step0 ( fn () => "hej" ) z val b = fn z => Fold . step0 ( fn () => 13 ) z val c = fn z => Fold . step0 ( fn () => ( 1 , 2 )) z ... f a $ = "hej" : streng f b $ = 13 : int f c $ = ( 1 , 2 ): int * int
Det enkleste SML-program kan skrives på én linje:
udskriv "Hej verden! \n "Men i betragtning af sprogets fokus på programmering i stor skala , bør dets indpakning i modulsproget stadig betragtes som minimal (nogle compilere fungerer kun med programmer på modulniveau).
detaljer signatur HELLO_WORLD = sig val helloworld : unit -> unit end struktur HelloWorld : HELLO_WORLD = struktur sjov helloworld () = udskriv "Hello World! \n " slutningGenerelt kan enhver funktion vælges som udgangspunkt for programmet, men i praksis giver det mening at følge almindeligt accepterede konventioner, så du bør tilføje følgende kode:
struktur Main = struct fun main ( navn : streng , args : strengliste ) : OS . _ proces . status = lad val _ = HelloWorld . helloworld () i OS . proces . succes ende endeFor SML/NJ compileren skal du også tilføje en specifik linje til strukturen :Main
val _ = SMLofNJ . exportFn ( "projekt1" , hoved );For programmer med flere moduler skal du også oprette en afhængighedssporingsprojektfil i compilermanageren (nogle compilere gør dette automatisk). For eksempel, for SML/NJ , skal du oprette en fil med sources.cmfølgende indhold:
gruppe signatur HELLO_WORLD struktur Hello World er helloworld-sig.sml helloworld.sml endeEn mere alsidig (men noget mere begrænset) mulighed med hensyn til understøttelse af forskellige compilere ville være at oprette en almindelig SML-kildekodefil med en lineær opregning af inkluderende filer:
brug "helloworld-sig.sml" ; brug "helloworld.sml" ;Uddatamaskinkoden for et minimalt program er også relativt stor (sammenlignet med Hello World- implementeringer i C), fordi selv det mindste SML-program skal indeholde sprogets runtime-system , hvoraf det meste er skraldeopsamleren . Man bør dog ikke opfatte størrelsen af kilde- og maskinkoderne i den indledende fase som tyngden af SML: deres årsag er sprogets intensive fokus på udviklingen af store og komplekse systemer. Yderligere vækst af programmer følger en meget fladere kurve end i de fleste andre statisk indtastede sprog, og overhead bliver knap mærkbar, når man udvikler seriøse programmer [71] .
Denne kode konverterer flad tekst til HTML på den enkleste måde og formaterer dialogen efter roller [72] .
Demonstration af arbejdeLad os sige, at vi har følgende tekstfil med navnet Henry.txt:
Westmoreland. Af kæmpende mænd har de fulde tre tusinde. Exeter. Der er fem til én; desuden er de alle friske. Westmoreland. 0, som vi nu havde her Men ti tusinde af de mænd i England Det virker ikke i dag! Kong Henrik V. Hvad er det ham, der ønsker det? Min fætter Westmoreland? Nej, min skønne fætter: Hvis vi er mærket til at dø, er vi nok At gøre vores land tab; og om at leve Jo færre mænd, jo større andel af ære.Kald derefter programmet med følgende linje:
val_ = htmlCvt " Henry.txt "Vil oprette en fil med Henry.txt.htmlfølgende indhold:
<P><EM>Westmoreland</EM>. Af kæmpende mænd har de fulde tre tusinde. <P><EM>Exeter</EM>. Der er fem til én; desuden er de alle friske. <P><EM>Westmoreland</EM>. 0, som vi nu havde her <br>Men en ti tusind af disse mænd i England <br>Det virker ikke i dag! <P><EM>Kong Henrik V</EM>. Hvad er det ham, der ønsker det? Hvad er min fætter Westmoreland? Nej, min skønne fætter: <br>Hvis vi er mærket til at dø, er vi nok <br>At gøre vores land tab; og om at leve <br>Jo færre mænd, jo større andel af ære.Denne fil kan åbnes i en browser ved at se følgende:
Westmoreland. Af kæmpende mænd har de fulde tre tusinde.
Exeter. Der er fem til én; desuden er de alle friske.
Westmoreland. 0, som vi nu havde her
Men ti tusinde af de mænd i England
, som ikke gør noget arbejde i dag!
Kong Henrik V. Hvad er det ham, der ønsker det?
Min fætter Westmoreland? Nej, min smukke fætter:
Hvis vi er mærket til at dø, er vi nok
til at gøre vores land tab; og hvis man skal leve,
jo færre mænd, jo større andel af ære.
Til opgaven med at slå en streng op i en ordbog, kombinerer ternære træer lynhastigheden af præfikstræer med hukommelseseffektiviteten af binære træer .
type key = Key . ord_key type item = Nøgle . ord_key list datatype sæt = LEAF | NODE af { key : key , lt : set , eq : set , gt : set } val tom = LEAF undtagelse Allerede til stede sjovt medlem (_, LEAF ) = falsk | medlem ( h::t , NODE { key , lt , eq , gt }) = ( case Key . compare ( h , key ) af EQUAL => medlem ( t , eq ) | MINDRE => medlem ( h::t , lt ) | STØRRE => medlem ( h::t , gt ) ) | medlem ([], NODE { key , lt , eq , gt }) = ( case Key . compare ( Key . sentinel , key ) af EQUAL => sand | MINDRE => medlem ([], lt ) | STØRRE => medlem ([], gt ) ) sjovt insert ( h::t , LEAF ) = NODE { key = h , eq = insert ( t , LEAF ), lt = LEAF , gt = LEAF } | indsæt ([], LEAF ) = NODE { key = Key . sentinel , eq = LEAF , lt = LEAF , gt = LEAF } | indsæt ( h::t , NODE { key , lt , eq , gt }) = ( case Key . compare ( h , key ) af EQUAL => NODE { key = key , lt = lt , gt = gt , eq = indsæt ( t , eq )} | MINDRE => NODE { key = key , lt = indsæt ( h::t , lt ), gt = gt , eq = eq } | STØRRE => NODE { key = key , lt = lt , gt = indsæt ( h::t , gt ), eq = eq } ) | indsæt ([], NODE { key , lt , eq , gt }) = ( case Key . compare ( Key . sentinel , key ) af EQUAL => hæv AlleredePresent | LESS => NODE { key = key , lt = indsæt ([ ], lt ), gt = gt , eq = eq } | STØRRE => NODE { key = key , lt = lt , gt = indsæt ([], gt ), eq = eq } ) sjov tilføje ( l , n ) = indsæt ( l , n ) håndtag AlleredeNuværende => nDenne kode bruger en basisstruktur , Keyder kan sammenlignes med signatur ORD_KEY, såvel som en global type order(over hvilken især funktionen er defineret Key.compare):
datatype rækkefølge = MINDRE | LIG | STØRREDe typiske fordele ved funktionel programmering ( typesikkerhed , automatisk hukommelsesstyring , et højt abstraktionsniveau osv.) kommer til udtryk ved at sikre programmernes pålidelighed og overordnede ydeevne, og i kritiske, især store opgaver, hastighed ofte spiller en sekundær rolle. Vægten på disse egenskaber har historisk set ført til, at mange effektive datastrukturer (arrays, strenge, bitstrenge) ofte ikke er tilgængelige for programmører i funktionelle sprog, så funktionelle programmer er normalt mærkbart mindre effektive end tilsvarende C -programmer . [73]
ML giver i starten ret god finkornet hastighedskontrol , men historisk har ML-implementeringer været ekstremt langsomme. Men tilbage i begyndelsen af 1990'erne læste Andrew Appel [74] , at SML-sproget er hurtigere end C -sproget , i det mindste når man arbejder intensivt med komplekse strukturerede data (men SML hævder ikke at være en erstatning for C i problemer med systemprogrammering ). I løbet af de næste par år førte hårdt arbejde med udviklingen af compilere til, at hastigheden for udførelse af SML-programmer steg med 20-40 gange [75] .
I slutningen af 1990'erne satte Steven Wicks sig for at opnå den højest mulige ydeevne fra SML-programmer og skrev en defunctorizer til SML/NJ , som straks viste en stigning i hastigheden med yderligere 2-3 gange. Yderligere arbejde i denne retning førte til skabelsen af MLton compileren , som i midten af 2000'erne af det 21. århundrede viste en stigning i hastighed i forhold til andre compilere med et gennemsnit på to størrelsesordener [45] , konkurrerende med C (for flere detaljer, se MLton ).
Strategien med automatisk hukommelsesstyring baseret på regionsinferens eliminerer omkostningerne ved initialisering og frigivelse af hukommelse fra programudførelse (det vil sige, den implementerer skraldindsamling på kompileringsstadiet). ML Kit- kompileren bruger denne strategi til at løse problemer i realtid , selvom den er ringere end MLton med hensyn til optimeringsmuligheder.
Baseret på SML/NJ frontend , blev en compiler til kildekode i C udviklet - sml2c . Det producerer kode af god kvalitet, men det er bemærkelsesværdigt, at " først til C, derefter til native " kompileringsskemaet sænker ydeevnen med op til to gange sammenlignet med direkte kompilering af SML til native kode på grund af semantiske forskelle mellem SML og C [5] .
Nogle SML-kompilere giver mulighed for at profilere koden for at bestemme de funktioner, der tager mest processortid (og resultatet er altid uventet) [73] , hvorefter du kan fokusere på at optimere dem ved hjælp af SML, eller flytte dem til C kode via FFI .
Sprogets teoretiske grundlag er den polymorf-typede lambdaregning (System F) , begrænset af Let-polymorfisme .
"Definitionen"Den officielle "standard" for sproget er The Definition , udgivet som en bog . Definitionen er formuleret i strenge matematiske termer og har dokumenteret pålidelighed . Konsistens af definitionen giver en person mulighed for at kontrollere programmets korrekthed og beregne dets resultat uden at køre en specifik compiler; men på den anden side kræver definitionen en høj grad af færdighed at forstå og kan ikke tjene som lærebog i sproget [74] .
Bevisbarheden af pålidelighed kom ikke af sig selv - Definitionen blev revideret flere gange, før den så dagens lys. Mange sprog er afhængige af generelle teorier, men under udvikling bliver de næsten aldrig testet for sikkerheden ved at dele specifikke sprogelementer, der er særlige anvendelser af disse teorier, hvilket uundgåeligt fører til inkompatibilitet mellem sprogimplementeringer. Disse problemer ignoreres enten eller præsenteres som et naturligt fænomen ( eng. "not a bug, but a feature" ), men i virkeligheden er de forårsaget af, at sproget ikke har været udsat for matematisk analyse [76] .
detaljerDen originale definition, " The Definition of Standard ML ", blev offentliggjort i 1990 [2] . Et år senere blev "Comments on the Definition" (" Kommentarer til Standard ML ") offentliggjort, som forklarer de anvendte tilgange og notationer [77] . Sammen danner de specifikationen for det sprog, der nu er kendt som " SML'90 ". I løbet af de følgende år dukkede en række kritikpunkter og forslag til forbedring op (en af de mest kendte er Harper-Lilybridges gennemsigtige summer ), og i 1997 blev mange af disse samlet i en revideret version af definitionen, " Definitionen af Standard ML: Revideret " [3] , der definerer en version af SML'97- sproget , der er bagudkompatibel med det tidligere. Den reviderede definition bruger principperne beskrevet i 1991-kommentarerne, så de, der har til hensigt at studere SML-definitionen grundigt, rådes til at studere SML'90 først, og først derefter SML'97. [78]
Med tiden blev der fundet en række uklarheder og udeladelser i teksten til definitionen [79] [80] [81] . Men de forringer ikke definitionens strenghed i det væsentlige - beviset for dens pålidelighed blev mekaniseret i Twelf [82] . De fleste implementeringer overholder definitionen ganske strengt, afvigende i tekniske funktioner - binære formater, FFI osv., såvel som i fortolkningen af tvetydige steder i definitionen - alt dette fører til behovet for en vis ekstra indsats (meget mindre end for de fleste andre sprog) for at sikre perfekt portabilitet af rigtige SML-programmer mellem implementeringer (små programmer har i de fleste tilfælde ingen porteringsproblemer).
SML-definitionen er et eksempel på strukturel operationel semantik ; det er ikke den første formelle definition af sproget, men den første, der er utvetydigt forstået af kompilatorudviklere [83] .
Definitionen opererer på semantiske objekter , der beskriver deres betydning ( betydning ). I indledningen understreger forfatterne, at det er semantiske objekter (som afhængigt af det specifikke sprog kan omfatte begreber som en pakke, modul, struktur, undtagelse, kanal, type, procedure, link, medbrug osv.) og ikke syntaks , definere en konceptuel repræsentation af et programmeringssprog, og det er på dem, definitionen af ethvert sprog skal bygges [84] .
Indhold
Ifølge definitionen er SML opdelt i tre sprog, bygget oven på hinanden: et bundlag kaldet " Kernesproget " ( kernesproget ), et mellemlag kaldet " moduler " ( moduler ) og et lille øverste lag kaldet " Programmer " ( Programmer ), som er en samling af topniveaudefinitioner ( topniveaudeklarationer ).
Definitionen omfatter omkring 200 slutningsregler ( inferens ), skrevet i form af en almindelig brøk, hvor den formaliserede sætning ML er i tællerpositionen, og konsekvensen, som kan konkluderes, hvis sætningen er korrekt, er i nævnerpositionen .
Definitionen skelner mellem tre hovedfaser i sproget [85] [86] : parsing ( parsing ), udvikling ( elaboration ) og evaluering ( evaluation ). Working out refererer til statisk semantik; beregning - til dynamisk. Men evalueringen her skal ikke forveksles med execution ( execution ): SML er et udtryksbaseret sprog ( expression-based language ), og at få et resultat ved at anvende en funktion på alle argumenter kaldes execution ( execution ), og "evaluering af en funktion" betyder at bygge en definition af det selv. Det skal også bemærkes, at understøttelsen af currying på sproget betyder, at alle funktioner er repræsenteret ved lukninger , og det betyder igen, at det er forkert at bruge udtrykket "funktionskald". I stedet for at kalde , bør vi tale om funktionsapplikation ( funktionsapplikation ) - funktionen kan simpelthen ikke kaldes, før den modtager alle argumenterne; delvis anvendelse af en funktion betyder evaluering af en ny funktion (en ny lukning ). For hvert af sprogets lag (kerne, moduler, programmer) beskrives statisk og dynamisk semantik separat, det vil sige stadierne af analyse, udvikling og beregning.
En særlig implementering af sproget er ikke påkrævet for at foretage alle disse skel, de er kun formelle [86] . Faktisk er den eneste implementering, der stræber efter at håndhæve dem strengt, HaMLet . Især betyder produktion uden evaluering det traditionelle begreb kompilering.
Evalueringen af hver definition i løbet af programmet ændrer tilstanden af det globale miljø ( miljø på øverste niveau ), kaldet grundlaget . Formelt er programmets udførelse beregningen af et nyt grundlag som summen af det indledende grundlag og programdefinitioner. Standardbiblioteket i SML er "standardgrundlaget", som er tilgængeligt for alle programmer fra begyndelsen, og kaldes derfor blot Basis. Selve definitionen indeholder kun det indledende grundlag ( initial basis ), der indeholder de minimum nødvendige definitioner; det mere omfattende Basis blev standardiseret meget senere, efter at have gennemgået en længere udvikling i praksis .
Harper-Stone semantikHarper-Stone semantik ( HS semantik for kort ) er en fortolkning af SML i en maskinskrevet ramme . XC-semantikken for SML er defineret gennem udviklingen af den eksterne SML til et internt sprog, som er en eksplicit maskinskrevet lambdaregning , og dermed fungerer som den typeteoretiske begrundelse for sproget. Denne fortolkning kan ses som et alternativ til Definitionen , der formaliserer "statiske semantiske objekter" i form af maskinskrevne lambda-calculus udtryk; og også som en deklarativ beskrivelse af genereringsreglerne for typestyrede compilere som TILT eller SML/NJ . Faktisk inkarnerer frontenden af TILT-kompileren denne semantik, selvom den blev udviklet flere år tidligere. [87] [88] [89]
Det interne sprog er baseret på Harper-Mitchells XML-sprog, men har et større sæt af primitiver og et mere udtryksfuldt modulsystem baseret på Harper-Lilybridges gennemsigtige summer . Dette sprog er velegnet til udvikling af mange andre sprog, hvis semantik er baseret på lambda-regningen , såsom Haskell og Scheme .
Denne tilgang er indbygget i det efterfølgende ML - projekt . Samtidig betragtes ændringer i sproget, som ikke påvirker det indre sprog, som et kortsigtet perspektiv ( eng. kortsigtet ), og som kræver ændringer - som et langsigtet perspektiv ( eng. langsigtet ).
Udviklerne af SML satte sproget til den højeste kvalitetsstandard fra starten, så tærsklen for kritik er meget højere end de fleste industrisprog. Omtaler om SML-sprogets mangler findes i den officielle presse lige så ofte som i C++-sproget og meget oftere end de fleste andre sprog, men årsagen er slet ikke en negativ holdning til SML - tværtimod, enhver kritik af SML fremsættes med en meget varm holdning til det. Selv en pedantisk analyse af manglerne ved SML ledsages normalt af dens beskrivelse som "et fantastisk sprog, det eneste seriøse sprog, der eksisterer " [90] . Med andre ord, forskerne dykker grundigt ned i manglerne og antyder, at selv når man tager dem i betragtning, viser SML sig at være mere at foretrække til brug i gigantiske videnskabstunge projekter end mange mere populære sprog, og ønsker at bringe SML til perfektion.
Fordele
Fejl
Hovedproblemet for SML-udvikleren i dag er det dårlige udviklingsniveau af miljøet (især IDE ) og biblioteksudvikling.
SML-sikkerhed betyder overhead på aritmetik: På grund af kravet om, at hver operation skal have identisk adfærd på hver platform, er overløbstjek , division med nul osv. væsentlige komponenter i enhver aritmetisk operation. Dette gør sproget til et ineffektivt valg til problemer med nummerknuser , især for pipelinede arkitekturer [91] .
Sammenligning med OKaml :
OKaml er den nærmeste slægtning til SML, efter at have skilt sig fra det selv før standardisering. OKaml er så bredt udviklet, at det nogle gange i spøg omtales som " SML++ ". Inden for masseprogrammering er OCaml betydeligt foran SML i popularitet; i akademiske kredse er SML meget oftere genstand for videnskabelig forskning. OCaml hovedudvikler Xavier Leroy er medlem af efterfølgeren ML bestyrelsen .
OCaml har en enkelt implementering, der inkluderer to compilere (til bytekode og til native), som er næsten identisk kompatible, og som konstant udvikler sig og tilbyder ikke kun bedre miljøer, men også mere og mere kraftfulde semantiske funktioner. SML har mange forskellige implementeringer, der følger den samme sprogdefinition og kernebibliotek, og nogle gange tilbyder yderligere funktioner.
De vigtigste forskelle er i semantikken for typeækvivalens. For det første i SML er funktorer generatorer, mens de i OCaml er applikative (se typeækvivalens i ML-modulsproget ). For det andet understøtter OCaml ikke lighedstypevariabler : lighedsoperationen accepterer objekter af enhver type, men kaster en undtagelse, hvis de er inkompatible .
Moderne versioner af OCaml inkluderer semantiske funktioner, der kun er tilgængelige individuelt i nogle SML-udvidelser, såsom:
Sammenligning med Haskell :
Haskell er arving til ML/SML (i denne forstand er der normalt ingen grundlæggende forskel mellem ML og SML). Begge sprog er baseret på Hindley -Milner-typesystemet , inklusive typeinferens , hvorfra der er mange ligheder [95] ( førsteklasses funktioner , typesikker parametrisk polymorfi , algebraiske datatyper og mønstermatchning på dem) .
Blandt de vigtigste forskelle er [95] [96] [97] [98] [99] [68] [100] :
Den formelle semantik af SML er fortolkningsorienteret , men de fleste af dens implementeringer er compilere (inklusive interaktive compilere), hvoraf nogle med sikkerhed konkurrerer i effektivitet med C -sproget , da sproget egner sig godt til global analyse. Af samme grund kan SML kompileres til kildekode på andre sprog på højt eller mellemniveau - for eksempel er der kompilatorer fra SML til C og Ada .
Sproget er baseret på stærk statisk polymorf typning, som ikke kun sikrer programverifikation på kompileringsstadiet, men også strengt adskiller mutabilitet , hvilket i sig selv øger potentialet for automatisk programoptimering - især forenkler implementeringen af skraldeopsamleren [104 ] .
Den første version af ML blev introduceret til verden i 1974 som et metasprog til at bygge interaktive beviser som en del af Edinburgh LCF (Logic for Computable Functions) systemet [2] . Det blev implementeret af Malcolm Newey, Lockwood Morris og Robin Milner på DEC10-platformen. Den første implementering var ekstremt ineffektiv, da ML-konstruktioner blev oversat til Lisp , som derefter blev fortolket [105] . Den første fuldstændige beskrivelse af ML som en del af LCF blev offentliggjort i 1979 [2] .
Omkring 1980 implementerede Luca Cardelli den første Vax ML compiler , og tilføjede nogle af hans ideer til ML. Cardelli overførte snart Vax ML til Unix ved hjælp af Berkley Pascal. Kørselstiden blev omskrevet i C , men det meste af compileren forblev i Pascal. Cardellis arbejde inspirerede Milner til at skabe SML som et almindeligt sprog i sig selv, og de begyndte at arbejde sammen i Edinburgh , hvilket resulterede i Edinburgh ML compileren , udgivet i 1984. I løbet af dette arbejde kom Mike Gordon med referencetyper og foreslog dem til Louis Damas, som senere lavede sin afhandling om dem [106] . Samtidig samarbejdede Cambridge med INRIA. Gerard Hugh fra INRIA overførte ML til Maclisp under Multics. INRIA udviklede deres egen dialekt af ML kaldet Caml, som senere udviklede sig til OCaml . Lawrence Paulson har optimeret Edinburgh ML , så ML-koden kører 4-5 gange hurtigere. Kort efter udviklede David Matthews Poly-sproget baseret på ML. Yderligere arbejde i denne retning førte til skabelsen af Poly/ML miljøet . I 1986 formulerede David McQueen ML-modulets sprog , og Andrew Appel sluttede sig til arbejdet Sammen påbegyndte de arbejdet med SML/NJ compileren , der både fungerede som en forskningsplatform for sprogudvikling og branchens første optimerende compiler. Mange af sprogimplementeringerne blev oprindeligt udviklet ved hjælp af SML/NJ og derefter promoveret .
Med erfaringerne fra storstilet udvikling blev en række mangler i sprogdefinitionen fra 1990 opdaget . Nogle af manglerne blev rettet i 1997-revisionen af definitionen [3] , men omfanget af revisionen eliminerer tabet af bagudkompatibilitet (koder tilpasser sig kosmetisk uden behov for at omskrive fra bunden). I 2004 udkom specifikationen for sammensætningen af Grundbiblioteket (et udkast til specifikationen går tilbage til 1996 ). Andre mangler er blevet rettet på andre sprog: ML skabte en hel familie af X-M-type sprog . Disse sprog har vundet popularitet på opgaven med sprogdesign og defineres ofte som " DSL'er for denotationel semantik . Forskere, der har været involveret i udviklingen og brugen af SML i næsten tre årtier, dannede i slutningen af det 20. århundrede et fællesskab for at skabe en ny sproglig efterfølger ML .
Faktisk var SML ikke den første i familien efter selve LCF/ML - det blev forudgået af sprog som Cardelli ML og Hope [9] . Franskmændene opretholder deres egen dialekt - Caml / OCaml [12] . Men når man siger "ML", mener mange mennesker "SML" [107] , og skriver endda gennem brøken: "ML/SML" [82] .
Den mest anbefalede [108] [109] [110] [111] [112] [113] lærebog om SML er ML for Working Programmer [107] af Lawrence Paulson (forfatter af HOL -systemet ) .
For en indledende introduktion til sproget, et kort (adskillige dusin sider) kursus " Introduction to Standard ML " af Robert Harper (tilgængelig i russisk oversættelse [114] ), som han brugte til at undervise i sproget og udvidede i løbet af de næste to årtier til mere større lærebog [115] .
Ricardo Pucellas bog [30] tjener som en tutorial til brug af sprogets standardbibliotek, forudsat en grundlæggende viden om det .
Andre lærebøger omfatter bøger af Gilmore [116] , Ullman [117] , Shipman [118] , Cummings online bog [119] .
Blandt guiderne til den professionelle brug af sproget kan man fremhæve bogen af Andrew Appel (hovedudvikler af SML/NJ ) " Modern compiler implementering i ML " [120] (denne bog har to tvillingesøstre : " Moderne compilerimplementering i Java " og " Moderne compilerimplementering i C ", som er ækvivalente i strukturen, men bruger andre sprog til at implementere de skitserede metoder). Der er også mange artikler publiceret i tidsskrifter såsom JFP , ML workshop osv. [121] [122]
SML fungerer sammen med OCaml som det første undervisningssprog til undervisning i programmering på mange universiteter rundt om i verden. Blandt anvendelige sprog har de sandsynligvis den laveste adgangstærskel af deres egne.
En væsentlig del af den eksisterende SML-kode er enten en implementering af dens egne compilere eller automatiske bevissystemer som HOL , Twelf og Isabelle (automatiseret teorem-bevissystem). Alle er gratis og åbne .
Der er dog også mere "mundanne", herunder proprietære produkter [123] .