ML standard | |
---|---|
Semantică | Formal , orientat spre interpretare |
Clasa de limba |
aplicativ , funcțional , imperativ |
Tipul de execuție | scop general |
Aparut in | 1984 [1] , 1990 [2] , 1997 [3] |
Autor | Robin Milner și alții |
Extensie de fișier | .sml |
Eliberare | Standard ML '97 (1997 ) |
Tip sistem | Hindley - Milner |
Implementări majore | multe |
Dialectele | Alice , SML# , Manticore și altele |
A fost influențat | Lisp , ISWIM , ML , POP-2 , Hope , Clear [4] |
influențat |
Erlang , OCaml , Haskell , succesor ML (sML) |
Licență | sursa deschisa |
Site-ul web | 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 , etc. ) , Windows , Cygwin , MinGW , Darwin , Solaris , Hurd , AIX , HP-UX |
Standard ML ( SML este un limbaj de programare compilatde uz general de ordin superior bazat pe sistemul de tip Hindley-Milner .
Se remarcă printr-o definiție precisă din punct de vedere matematic (care garantează identitatea semnificației programelor indiferent de compilator și hardware), care are o fiabilitate dovedită a semanticii statice și dinamice. Este un limbaj „în mare parte funcțional ” [7] [8] , adică suportă majoritatea caracteristicilor tehnice ale limbajelor funcționale , dar oferă și capabilități avansate de programare imperativă atunci când este necesar. Combină stabilitatea programelor, flexibilitatea la nivelul limbajelor tastate dinamic și viteza la nivelul limbajului C ; oferă suport excelent atât pentru prototipare rapidă, cât și pentru modularitate și programare la scară largă [9] [10] .
SML a fost primul limbaj compilat independent din familia ML și încă servește ca limbaj de ancorare în comunitatea de dezvoltare ML ( succesorul ML ) [11] . SML a fost primul care a implementat un sistem unic de module aplicative , limbajul modulului ML .
Limbajul este axat inițial pe programarea la scară largă a sistemelor software: oferă mijloace eficiente de abstractizare și modularitate , oferind o rată ridicată de reutilizare a codului și acest lucru îl face potrivit și pentru prototiparea rapidă a programelor, inclusiv la scară largă . De exemplu, în timpul dezvoltării compilatorului (pe atunci încă experimental) SML/NJ ( 60 de mii de linii per SML), uneori a fost necesar să se facă schimbări radicale în implementarea structurilor cheie de date care afectează zeci de module - iar noua versiune a compilatorului era gata în timpul zilei. [9] (Vezi și Concursul de programare ICFP 2008, 2009.) Cu toate acestea, spre deosebire de multe alte limbaje potrivite pentru prototipare rapidă , SML poate compila foarte eficient .
SML este cunoscut pentru pragul de intrare relativ scăzut și servește ca limbaj de predare în programare la multe universități din întreaga lume [12] . Este documentat pe larg sub formă de lucru și este folosit în mod activ de oamenii de știință ca bază pentru cercetarea elementelor noi ale limbajelor de programare și idiomurilor (a se vedea, de exemplu, polimorfismul tipurilor structurale ). Până acum, toate implementările limbajului (inclusiv cele învechite) au devenit open source și gratuite .
Limbajul are o definiție formală precisă din punct de vedere matematic ( ing. riguroasă ) numită „Definiție” ( ing. Definiția ). Pentru Definiție, este construită o dovadă de siguranță completă , care garantează stabilitatea programelor și un comportament previzibil chiar și cu date de intrare incorecte și posibile erori de programare. Chiar și un program SML cu erori se comportă întotdeauna ca un program ML: poate intra în calcul pentru totdeauna sau poate arunca o excepție , dar nu se poate bloca [13] .
SML este un limbaj preponderent funcțional ( în mare parte funcțional sau în primul rând funcțional ) [7] [8] , adică suportă majoritatea caracteristicilor tehnice ale limbajelor funcționale , dar oferă și capacități de programare imperative . Este denumită mai frecvent „ limbaj de ordin superior pentru a sublinia suportul pentru caracteristicile de primă clasă, în același timp distingându-l de limbile transparente referențial .
SML oferă suport remarcabil pentru programarea la scară largă prin cel mai puternic și mai expresiv sistem de module cunoscut ( ML Module Language ). SML implementează o versiune timpurie a limbajului modulului, care este un strat separat al limbajului: modulele pot conține obiecte limbaj de bază, dar nu invers [14] .
Spre deosebire de multe alte limbaje din familia ML ( OCaml , Haskell , F# , Felix, Opa, Nemerle și altele), SML este foarte minimalist: nu are programare nativă orientată pe obiecte , concurență , polimorfism ad-hoc , tastare dinamică . , generatoare de liste și multe alte caracteristici. Cu toate acestea, SML este ortogonal [15] (adică implementează minimul necesar, dar setul complet de elemente maxim diferite), ceea ce face relativ ușor să emulezi alte caracteristici, iar tehnicile necesare pentru aceasta sunt acoperite pe larg în literatură. . De fapt, SML vă permite să utilizați în mod arbitrar funcționalitatea de nivel înalt ca o primitivă pentru a implementa funcționalități chiar și de nivel superior [16] . În special, modelele de implementare ale claselor de tip și monadelor sunt construite folosind doar constructe SML standard, precum și instrumente de programare orientate pe obiecte [17] . Mai mult, SML este unul dintre puținele limbaje care implementează direct continuări de primă clasă .
Sistemul de tip Hindley-Milner (X-M) este o caracteristică distinctivă a ML și a descendenților săi. Asigură fiabilitatea programelor datorită detectării precoce a erorilor, reutilizării ridicate a codului , potențialului ridicat de optimizare , combinând aceste calități cu concizia și expresivitatea la nivelullimbajelor tipizate dinamic . Cele mai proeminente caracteristici inerente în X-M sunt polimorfismul de tip , precum și tipurile de date algebrice și potrivirea modelelor pe acestea.
Implementarea X-M în SML are următoarele caracteristici:
Spre deosebire de multe limbi, SML oferă o mare varietate de moduri de utilizare [21] :
În același timp, în anumite moduri, sunt posibile o varietate de platforme țintă și strategii de compilare :
Strategiile de compilare în sine diferă, de asemenea, semnificativ:
Restricție de valoare _ _ _
Structuri de controlModularitate
Sistemul de module SML este cel mai dezvoltat sistem de module din limbaje de programare. El repetă semantica ML de bază ( ing. Core ML ), astfel încât dependențele dintre componentele mari ale programului sunt construite ca dependențe de un nivel mic. Acest sistem de module este format din trei tipuri de module:
Structurile sunt similare cu modulele din majoritatea limbajelor de programare. Semnăturile servesc ca interfețe de structură, dar nu sunt legate rigid de anumite structuri, ci construiesc relații conform schemei „ mulți-la-mulți ” , permițându-vă să controlați în mod flexibil vizibilitatea componentelor structurii în funcție de nevoile contextului programului.
Functorii sunt „ funcții peste structuri ”, permițându-vă să spargeți dependențele de compilare și să descrie modulele parametrizate. Ele fac posibilă tastarea -descrierea în siguranță a calculelor pe componentele programului care în alte limbaje pot fi implementate doar prin metaprogramare [23] - ca șabloane C++ , doar fără durere și suferință [24] , sau limbajul macro Lisp , doar cu controlul static de siguranță al codului generat [23 ] . Majoritatea limbilor nu au nimic comparabil cu functorii [25] .
Diferența fundamentală dintre limbajul modulului ML este că rezultatul unui functor poate include nu numai valori, ci și tipuri și pot depinde de tipurile care fac parte din parametrul functor. Acest lucru face ca modulele ML să fie cele mai apropiate ca expresivitate de sistemele cu tipuri dependente , dar, spre deosebire de acestea din urmă, modulele ML pot fi reduse la un sistem plat F ω (vezi Module Language ML#F-Rossberg-Rousseau-Dreyer ).
Sintaxa limbajului este foarte scurtă, în ceea ce privește numărul de cuvinte rezervate ocupând o poziție intermediară între Haskell și Pascal [26] .
SML are o gramatică fără context , deși unele ambiguități sunt notate în ea. SML/NJ folosește LALR(1) , dar LALR(2) este prezent într-un singur loc.
Lista de cuvinte cheie de limbă ( identificatorii care se potrivesc cu acestea nu sunt permise) [27] :
abstype și, de asemenea, ca tip de date de caz , altfel se încheie eqtype excepția fn functor manevrare if in include infix infixr let local nonfix of op open orelse raise rec sharing sign signature struct structure apoi tastați val where while with withtypeDe asemenea, sunt permise identificatorii de caractere , adică numele de tip, date și funcții pot consta din următoarele caractere non-alfabetice:
! % & $ # + - * / : < = > ? @ \ ~ ' ^ |Numele acestor simboluri pot avea orice lungime [27] :
val ----> = 5 distracție !!? ©**??!! x = x - 1 infix 5 $^$^$^$ fun a $^$^$^$ b = a + b val :-|==>-># = Listă . foldrDesigur, utilizarea unor astfel de nume în practică nu este de dorit, dar dacă autorul anterior al codului menținut le-a folosit pe scară largă, atunci datorită definiției formale, devine posibil (și SML în sine face destul de ușor rezolvarea acestei probleme) scrierea unui preprocesor pentru corectarea mnemotecilor.
Sunt excluse doar următoarele șiruri de caractere:
: | ==> -> # :>Motivul acestei limitări constă în rolul lor special în sintaxa limbii:
: - adnotare explicită tip valoare | - separarea probelor = - separarea corpului funcției de antetul acestuia => - separarea corpului funcției lambda de antetul acesteia -> — constructor de tip funcțional (săgeată). # - acces la câmpul de înregistrare :> - potrivirea structurii cu semnăturaSML nu are o sintaxă încorporată pentru matrice și vectori (matrice constante). [|1,2,3|]Unele implementări acceptă sintaxa pentru tablouri ( ) și vectori ( ) într- o oarecare măsură #[1,2,3]ca extensie.
Operația de atribuire este scrisă ca în limbajele Pascal :x:=5
Biblioteca standard SML se numește Baza . A evoluat de-a lungul multor ani, fiind supus unor teste riguroase pe probleme reale bazate pe SML/NJ , proiectul său a fost publicat în 1996 [28] , iar apoi caietul de sarcini a fost publicat oficial în 2004 [29] . În această perioadă, deja apăreau manuale pentru folosirea lui [30] . Biblioteca de bază implementează doar minimul necesar de module: tipuri de date banale, aritmetică peste ele, intrare-ieșire , interfață independentă de platformă cu sistemul de operare etc., dar nu implementează funcționalități mai complexe (de exemplu, multithreading). Multe compilatoare oferă în plus diferite biblioteci experimentale.
Compilatorii pot folosi cunoștințele de bază pentru a aplica algoritmi pre-optimizați și tehnici de optimizare specializate: de exemplu, MLton folosește reprezentarea nativă a tipurilor de bază (corespunzând exact tipurilor de limbaj C primitive ), precum și cele mai simple tipuri agregate compuse din lor.
Ca și în majoritatea limbilor, SML Basis are o serie de convenții arhitecturale și sintactice specifice. În primul rând, acestea sunt componentele banale ale structurilor standard, cum ar fi combinatorii similari ca nume și semnături (cum ar fi fold). Mai mult, aceasta este o schemă care se aplică la majoritatea tipurilor de conversie în tip șir și invers .
Convertoare și scanereSchema standard pentru conversia la și de la un tip șir este încapsulată într-o struct StringCvt:
structura StringCvt : sig datatype radix = BIN | oct | DEC | HEX tipul de date realfmt = SCI al opțiunii int | FIX pentru opțiunea int | GEN al opțiunii int | CORECT tastați ( 'a , 'b ) reader = 'b -> ( 'a * 'b ) opțiunea val padLeft : char -> int -> string -> string val padRight : char -> int -> string -> string val splitl : ( char -> bool ) -> ( char , 'a ) reader -> 'a -> ( șir * 'a ) val takel : ( char -> bool ) -> ( char , 'a ) cititor -> 'a -> șir val dropl : ( char -> bool ) -> ( char , 'a ) cititor - > 'a -> 'a val skipWS : ( char , 'a ) reader -> 'a -> 'a tastați cs val scanString : (( char , cs ) reader -> ( 'a , cs ) reader ) -> șir -> 'o opțiune finalSchema de conversie nu se limitează la enumerarea bazelor sistemelor de numere, ca în C ( BIN, OCT, DEC, HEX). Se extinde la programarea de ordin superior , permițându-vă să descrieți operațiunile de citire a valorilor unor tipuri specifice din fluxuri abstracte și de scriere în ele, iar apoi să transformați operațiuni simple în altele mai complexe folosind combinatoare . Fluxurile pot fi fluxuri I/O standard sau doar tipuri agregate, cum ar fi liste sau șiruri. [31]
Cititori, adică valori de tip ('a,'b) reader. Intuitiv, un cititor este o funcție care ia un flux de tip ca intrare 'bși încearcă să citească o valoare de tip din acesta 'a, returnând fie valoarea citită și „restul” fluxului, fie NONEdacă nu reușește. Un tip important de cititoare sunt scanerele sau funcțiile de scanare. Pentru un anumit tip, Tfuncția de scanare are tipul
( char , 'b ) cititor -> ( T , 'b ) cititor- adică este un convertor de la un cititor de caractere la un cititor de acest tip. Scanerele sunt incluse în multe module standard, de exemplu, semnătura INTEGERinclude un scanner pentru numere întregi:
semnătură INTEGER = sig eqtype int ... val scan : StringCvt . radix -> ( char , 'a ) StringCvt . cititor -> 'a -> ( int * 'a ) opțiunea finalNumerele sunt citite atomic, dar cititorii pot citi din fluxuri și lanțuri element cu element, de exemplu, caracter cu caracter, o linie dintr-un șir:
fun stringGetc ( s ) = let val ss = Substring . plin ( e ) în cazul în care Subșir . getc ( ss ) of NONE => NONE | SOME ( c , ss' ) => SOME ( c , Substring . string ( ss' )) final ; stringGetc ( "bună ziua" ); (* val it = SOME (#"h","ello"): (car * șir) opțiune *) stringGetc ( #2 ( valOf it ) ); (* val it = SOME (#"e","llo"): (car * șir) opțiune *) stringGetc ( #2 ( valOf it ) ); (* val it = SOME (#"l","lo"): (car * șir) opțiune *) stringGetc ( #2 ( valOf it ) ); (* val it = SOME (#"l","o"): (car * șir) opțiune *) stringGetc ( #2 ( valOf it ) ); (* val it = SOME (#"o",""): (car * șir) opțiune *) stringGetc ( #2 ( valOf it ) ); (* val it = NONE : (car * șir) opțiune *)Scanerele vă permit să creați cititori din cititorii existenți, de exemplu:
val stringGetInt = Int . scanează StringCvt . DEC șirGetcStructura StringCvtoferă, de asemenea, o serie de funcții de ajutor. De exemplu, splitlși takelcombinați droplcititorii de caractere cu predicate de caractere pentru a permite filtrarea fluxurilor.
De remarcat că nu cititorii de caractere sunt un caz special de cititori în general, ci invers [32] . Motivul pentru aceasta este că extragerea unei subsecvențe dintr-o secvență este o generalizare a extragerii unui subșir dintr-un șir.
destul de strict . Diferențele constau în detalii tehnice, precum formatul binar al modulelor compilate separat, implementarea FFI etc. În practică, un program real trebuie să înceapă de la o anumită bază (un set minim de tipuri, facilități de intrare-ieșire) . , etc.). Cu toate acestea, Definiția impune doar cerințe minime asupra compoziției bazei inițiale, astfel încât singurul rezultat observabil al unui program corect conform Definiției este că programul se termină sau aruncă o excepție, iar majoritatea implementărilor sunt compatibile la acest nivel [33] .
Cu toate acestea, chiar și baza standard are unele probleme potențiale de portabilitate. De exemplu [33] , o constantă conține valoarea celui mai mare număr întreg posibil, încapsulată în tipul opțional , și trebuie preluată fie prin potrivirea modelului, fie printr-un apel de funcție . Pentru tipurile de dimensiuni finite, valoarea este , iar ambele metode de extragere sunt echivalente. Dar este egal , deci accesarea directă a conținutului prin intermediul va face o excepție . Deschis implicit , de exemplu, în compilatorul Poly/ML . Int.maxIntvalOfIntN.maxIntSOME(m)IntInf.maxIntNONEvalOf OptionIntInf
Cu ceva efort, este posibil să se dezvolte programe care sunt portabile liber între toate implementările curente ale limbajului. Un exemplu de astfel de program este HaMLet .
Până în prezent, Standard ML a devenit complet public: toate implementările sunt gratuite și open source și distribuite sub cele mai loiale licențe ( în stil BSD , MIT ); textele Definiției limbii (atât în versiunea din 1990, cât și în versiunea revizuită din 1997) și ale Specificației de bază sunt de asemenea disponibile gratuit .
SML are un număr mare de implementări. O parte semnificativă dintre ele sunt scrise în SML propriu-zis; excepțiile sunt runtimele unor compilatoare scrise în C și Assembler , precum și sistemul Poplog .
Compilatoare la cod nativ
Verificarea compilatoarelor
Compilatoare la bytecodes și Java
Implementări de nivel superior
Implementări învechite
SML#
SML# [56] extinde conservator SML cu polimorfism de înregistrare în modelul Atsushi Ohori , pe care SML# îl folosește pentru a încorpora fără probleme SQL în codul SML pentru programarea intensivă a bazelor de date.
Simbolul lire sterline ( #) din numele limbii simbolizează selectorul (operația de selectare a unui câmp dintr-o înregistrare). Compilatorul cu același nume pretinde performanțe bune. Dezvoltat și dezvoltat la Institutul Tohoku (Japonia) sub îndrumarea lui Ohori însuși.
AliceAlice ML extinde în mod conservator SML cu primitive pentru programarea concomitentă bazată pe strategia exotică de evaluare „ apel după viitor ” , soluția de constrângeri și toate elementele consistente ale designului ML succesor . În special, Alice acceptă module de primă clasă sub formă de pachete cu încărcare dinamică și tastare dinamică , ceea ce permite implementarea calculului distribuit . Alice oferă, de asemenea, futures proprietăți de primă clasă, inclusiv furnizarea de futures la nivel de modul (structuri viitoare și semnături viitoare). Compilatorul folosește o mașină virtuală. Dezvoltat și dezvoltat la Universitatea Saarland sub conducerea lui Andreas Rossberg.
ML concurentConcurrent ML (CML) o bibliotecălimbaj încorporabilcare extinde SMLde programare concurentă de ordin superior bazate pemesageriesincronde primă clasă. Inclus în distribuția standard a compilatoarelor SML/NJ șiMLton. Ideile de bază ale CML sunt în centrul proiectului Manticore și sunt încorporate în proiectul ML succesor [11] .
ManticoreManticore [40] implementează suport cuprinzător pentru programarea simultană și paralelă , de la descompunerea logică a unui sistem în procese până la controlul fin asupra celei mai eficiente utilizări a sistemelor multi-core . Manticore se bazează pe un subset de SML, excluzând matricele mutabile și referințele, adică este un limbaj pur , menținând o ordine strictă de evaluare . Mecanismele de concurență explicită și paralelism grosier ( fire ) se bazează pe CML , în timp ce mecanismele de paralelism fine ale stratului de date ( matrice paralele ) sunt similare cu NESL . Compilatorul cu același nume generează cod nativ .
MLPolyRMLPolyR este un limbaj de jucărie care se bazează pe un subset simplu de SML și îi adaugă mai multe niveluri de siguranță de tip . Scopul proiectului este de a aprofunda studiul polimorfismului de înregistrare pentru nevoile succesorului proiectului ML . Sistemul inovator de tip MLPolyR rezolvă problema expresiei și garantează nicio excepție netratată în programe.
Dezvoltat sub conducerea lui Matthias Blum (autorul NLFFI ) la Toyota Institute of Technology din Chicago , SUA .
MythrylMythryl [57] este o variantă de sintaxă a SML menită să accelereze dezvoltarea POSIX . Noua sintaxă este împrumutată în mare măsură de la C; terminologia a fost, de asemenea, revizuită pentru a fi mai tradițională (de exemplu, functorii au fost redenumite în generice ). În același timp, autorii subliniază că nu intenționează să creeze „o altă gură de caracteristici ale limbajului”, ci aderă la natura minimalistă a SML și se bazează pe Definiția sa . Implementarea este o furcă a SML/NJ .
Altele
Nu există cerințe pentru proiectarea programelor în SML, deoarece gramatica limbii este complet lipsită de context și nu conține ambiguități evidente. Cu toate acestea, observă probleme speciale, de exemplu, la trecerea operatorului de multiplicare, op *paranteza de închidere trebuie separată printr-un spațiu ( (op * )), deoarece atunci când sunt scrise în formă continuă, multe implementări (nu toate) necesită câteva caractere *)pentru a închide un comentariu. în cod și generează o eroare.
Cu toate acestea, există încă anumite recomandări menite să îmbunătățească lizibilitatea, modularitatea și reutilizarea codului, precum și detectarea timpurie a erorilor și creșterea posibilității de modificare (dar nu și pentru introducerea de informații despre tipuri în identificatori, așa cum se face, de exemplu, în notația maghiară ) [ 64 ] . În special, SML recomandă o convenție de denumire pentru identificatorii de nivel de bază similară cu cea cerută de Haskell : fooBarpentru valori, foo_barpentru constructori de tip , FooBarpentru funcții de constructor (unii compilatori chiar emit un avertisment dacă este încălcat). Acest lucru se datorează naturii potrivirii modelelor, care în general nu poate face distincția între intrarea variabilă locală și utilizarea constructorului de tip nul , astfel încât greșelile de scriere pot duce la erori (relativ ușor detectabile) [65] .
Cele mai neobișnuite și neașteptate pot fi:
Pentru proceduri , se adoptă același mod ca și în C : procedurile sunt reprezentate de funcții care returnează o valoare de un singur tip :
fun p s = print s (* val p = fn : sting -> unit *) Calcul secvenţial să se termine D în E fun foo ... = let val _ = ... in ... endAceastă expresie -expansiune ( în engleză eta-expansion )eeste o expresiefn z => e z, adică un înveliș al expresiei originale într-o funcție lambda , undeznu apare îne. Desigur, acest lucru are sens doar dacăeare un tip de săgeată , adică este o funcție. Această extensie obligă evaluarea să fie întârziatăepână când funcția este aplicată și să fie reevaluată de fiecare dată când este aplicată. Această tehnică este folosită în SML pentru a depăși limitările de expresivitate asociate cu semantica valorice . Termenul „ eta -expansiune” este împrumutat de la eta- transformarea în calculul lambda , însemnând, dimpotrivă, reducerea unei expresiiladacă aceastanu apare în( eta - contracție). [67] [68]fn z => e zeze
Valori indexate pe tipuriValori indexate pe tipuri ( în engleză type-indexed values ) este o tehnică care vă permite să introduceți suport pentru polimorfismul ad-hoc în SML (care îi lipsește inițial) [69] . Există o serie de variante ale sale, inclusiv cele care vizează sprijinirea programării cu drepturi depline orientate pe obiecte [17] .
Fold„ Fold ” [70] este o tehnică care introduce o serie de expresii obișnuite în SML, inclusiv funcții variadice, parametri de funcție numiți, valori implicite ale parametrilor, suport sintactic pentru matrice în cod, actualizarea funcțională a înregistrărilor și o reprezentare cosmetică a tastării dependente . pentru a oferi siguranța de tip a funcțiilor precum printf.
PrincipiuEste necesar să se definească trei funcții - foldși - step0astfel $încât următoarea egalitate să fie adevărată:
pliază ( a , f ) ( pas 0 h1 ) ( pas 0 h2 ) ... ( pas 0 hn ) $ = f ( hn (... ( h2 ( h1 a ))))Definiția lor minimă este laconică:
distracție $ ( a , f ) = f a structura Fold = struct fun fold ( a , f ) g = g ( a , f ) fun step0 h ( a , f ) = fold ( h a , f ) finalO implementare mai avansată vă permite să controlați tipurile de expresii folosind Fold.
Exemplu: număr variabil de argumente ale funcției val sum = fn z => Pliere . fold ( 0 , fn s => s ) z fun a i = Fold . step0 ( fn s => i + s ) ... sum ( a 1 ) ( a 2 ) ( a 3 ) $ (* val it : int = 6 *)
Exemplu: enumerați literali val list = fn z => Fold . fold ([], rev ) z val ' = fn z => Fold . pasul 1 ( op :: ) z ... lista 'w 'x 'y 'z $
Exemplu: tipuri dependente (cosmetice). val f = fn z => Îndoire . pliază ((), id ) z val a = fn z => Pliază . step0 ( fn () => "bună ziua" ) z val b = fn z => Îndoire . step0 ( fn () => 13 ) z val c = fn z => Pliere . step0 ( fn () => ( 1 , 2 )) z ... f a $ = "bună ziua" : șir f b $ = 13 : int f c $ = ( 1 , 2 ): int * int
Cel mai simplu program SML poate fi scris într-o singură linie:
printează „Bună lume! \n ”Cu toate acestea, având în vedere focalizarea limbajului pe programarea la scară largă , învelișul său în limbajul modulului ar trebui să fie considerat minim (unii compilatoare funcționează numai cu programe la nivel de modul).
Detalii semnătură HELLO_WORLD = sig val helloworld : unit -> unit end structura HelloWorld : HELLO_WORLD = struct fun helloworld () = tipări „Hello World! \n ” endÎn general, orice funcție poate fi aleasă ca punct de plecare al programului, dar în practică este logic să urmați convențiile general acceptate, așa că ar trebui să adăugați următorul cod:
structura Main = struct fun main ( nume : string , args : string list ) : OS . proces . status = let val _ = HelloWorld . helloworld () în sistemul de operare . proces . sfârșitul succesului _Pentru compilatorul SML/NJ , trebuie de asemenea să adăugați o linie specifică structurii :Main
val _ = SMLofNJ . exportFn ( "proiect1" , principal );Pentru programele cu mai multe module, trebuie, de asemenea, să creați un fișier proiect de urmărire a dependențelor în managerul compilatorului (unii compilatori fac acest lucru automat). De exemplu, pentru SML/NJ , creați un fișier cu sources.cmurmătorul conținut:
grup semnătură HELLO_WORLD structura Hello World este helloworld-sig.sml helloworld.sml SfârşitO opțiune mai versatilă (dar ceva mai limitată) în ceea ce privește suportul de către diverși compilatori ar fi crearea unui fișier cod sursă SML obișnuit cu o enumerare liniară a fișierelor include:
utilizați „helloworld-sig.sml” ; utilizați „helloworld.sml” ;Codul mașinii de ieșire pentru un program minim este, de asemenea, relativ mare (comparativ cu implementările Hello World în C), deoarece chiar și cel mai mic program SML trebuie să includă sistemul de rulare al limbajului , dintre care cea mai mare parte este colectorul de gunoi . Cu toate acestea, nu ar trebui să percepem dimensiunea codurilor sursă și a mașinii la etapa inițială ca fiind greutatea SML: motivul lor este concentrarea intensă a limbajului pe dezvoltarea sistemelor mari și complexe. Creșterea ulterioară a programelor urmează o curbă mult mai plată decât în majoritatea celorlalte limbaje tipizate static, iar overheadul devine abia vizibil atunci când se dezvoltă programe serioase [71] .
Acest cod convertește textul plat în HTML în cel mai simplu mod, formatând dialogul pe roluri [72] .
Demonstrație de muncăSă presupunem că avem următorul fișier text numit Henry.txt:
Westmoreland. De bărbați luptători au trei zeci de mii. Exeter. Sunt cinci la unu; in plus, toate sunt proaspete. Westmoreland. 0 pe care le aveam acum aici Dar o zece mii dintre acești bărbați în Anglia Asta nu lucrează azi! Regele Henric al V-lea. Ce este cel care dorește așa ceva? Vărul meu Westmoreland? Nu, verișoara mea: Dacă suntem marcați să murim, suntem de ajuns Să facem pierderea țării noastre; iar dacă să trăiască Cu cât sunt mai puțini bărbați, cu atât cota de onoare este mai mare.Apoi apelați programul cu următoarea linie:
val_ = htmlCvt " Henry.txt "Va crea un fișier cu Henry.txt.htmlurmătorul conținut:
<P><EM>Westmoreland</EM>. De bărbați luptători au trei zeci de mii. <P><EM>Exeter</EM>. Sunt cinci la unu; in plus, toate sunt proaspete. <P><EM>Westmoreland</EM>. 0 pe care le aveam acum aici <br>Dar o zece mii dintre acești bărbați din Anglia <br>Asta nu funcționează astăzi! <P><EM>Regele Henric al V-lea</EM>. Ce este cel care își dorește așa ceva? - Vărul meu Westmoreland? Nu, verișoara mea: <br>Dacă suntem marcați să murim, suntem de ajuns <br>Pentru a ne pierde țara; iar dacă să trăiască <br>Cu cât sunt mai puțini bărbați, cu atât cota de onoare este mai mare.Acest fișier poate fi deschis într-un browser , văzând următoarele:
Westmoreland. De bărbați luptători au trei zeci de mii.
Exeter. Sunt cinci la unu; in plus, toate sunt proaspete.
Westmoreland. 0 pe care-l aveam acum aici.
Dar o zece mii dintre acei oameni din Anglia
care nu lucrează astăzi!
Regele Henric al V-lea. Ce este cel care dorește așa ceva?
Vărul meu Westmoreland? Nu, vărul meu frumos:
Dacă suntem însemnați să murim, suntem îndeajuns
Ca să ne pierdem
țara; iar dacă să trăiești,
cu cât sunt mai puțini oameni, cu atât mai mare parte din onoare.
Pentru sarcina de a căuta un șir într-un dicționar, arborii ternari combină viteza fulgerului a arborilor de prefix cu eficiența memoriei arborilor binari .
tip key = Key . ord_key type item = Cheie . ord_key list datatype set = LEAF | NODE de { key : key , lt : set , eq : set , gt : set } val empty = LEAF exception DejaPrezentă membru distractiv (_, LEAF ) = fals | membru ( h::t , NODE { key , lt , eq , gt }) = ( case Key . compara ( h , key ) din EQUAL => membru ( t , eq ) | LESS => membru ( h::t , lt ) | MAI MARE => membru ( h::t , gt ) ) | membru ([], NODE { key , lt , eq , gt }) = ( case Key . compare ( Key . sentinel , key ) of EQUAL => true | LESS => membru ([], lt ) | GREATER => membru ([], gt ) ) distractiv insert ( h::t , LEAF ) = NODE { key = h , eq = insert ( t , LEAF ), lt = LEAF , gt = LEAF } | insert ([], LEAF ) = NODE { cheie = Cheie . santinel , eq = LEAF , lt = LEAF , gt = LEAF } | insert ( h::t , NODE { key , lt , eq , gt }) = ( case Key . compara ( h , key ) of EQUAL => NODE { key = key , lt = lt , gt = gt , eq = insert ( t , eq )} | LESS => NODE { key = key , lt = insert ( h::t , lt ), gt = gt , eq = eq } | GREATER => NODE { key = key , lt = lt , gt = insert ( h::t , gt ), eq = eq } ) | insert ([], NODE { key , lt , eq , gt }) = ( case Key . compare ( Key . sentinel , key ) of EQUAL => raise DejaPrezentă | LESS => NODE { key = key , lt = insert ([ ], lt ), gt = gt , eq = eq } | MAI MAR => NODE { key = key , lt = lt , gt = insert ([], gt ), eq = eq } ) fun add ( l , n ) = insert ( l , n ) handle AlreadyPresent => nAcest cod folosește o structură de bază Keycomparabilă cu semnătura ORD_KEY, precum și un tip global order(peste care, în special, funcția este definită Key.compare):
Ordinea tipului de date = LESS | EGAL | MAI MAREAvantajele tipice ale programării funcționale ( siguranța tipului , gestionarea automată a memoriei , un nivel ridicat de abstractizare etc.) se manifestă în asigurarea fiabilității și a performanței generale a programelor, iar în sarcinile critice, în special la scară largă , viteza adesea joacă un rol secundar. Accentul pus pe aceste proprietăți a condus istoric la faptul că multe structuri eficiente de date (matrice, șiruri de caractere, șiruri de biți) nu sunt adesea disponibile programatorilor în limbaje funcționale, astfel încât programele funcționale sunt de obicei vizibil mai puțin eficiente decât programele C echivalente . [73]
ML furnizează inițial un control destul de bun al vitezei , cu toate acestea, istoric , implementările ML au fost extrem de lente. Cu toate acestea, la începutul anilor 1990, Andrew Appel a citit [74] că limbajul SML este mai rapid decât limbajul C , cel puțin atunci când lucrează intens cu date structurate complexe (dar SML nu pretinde a fi un înlocuitor pentru C în probleme de programare a sistemului ). În următorii câțiva ani, munca asiduă la dezvoltarea compilatoarelor a dus la faptul că viteza de execuție a programelor SML a crescut de 20-40 de ori [75] .
La sfârșitul anilor 1990, Steven Wicks și-a propus să obțină cea mai mare performanță posibilă din programele SML și a scris un defunctorizator pentru SML/NJ , care a arătat imediat o creștere a vitezei de încă 2-3 ori. Lucrările ulterioare în această direcție au condus la crearea compilatorului MLton , care, la mijlocul anilor 2000 ai secolului XXI, a arătat o creștere a vitezei față de alte compilatoare cu o medie de două ordine de mărime [45] , concurând cu C (pentru mai multe detalii, vezi MLton ).
Strategia de gestionare automată a memoriei bazată pe inferența regiunii elimină costul inițializării și eliberării memoriei din execuția programului (adică implementează colectarea gunoiului în etapa de compilare). Compilatorul ML Kit folosește această strategie pentru a rezolva probleme în timp real , deși este inferior MLton în ceea ce privește capabilitățile de optimizare.
Pe baza SML/NJ front-end , a fost dezvoltat un compilator la codul sursă în C - sml2c . Produce cod de bună calitate, dar este de remarcat faptul că schema de compilare „ întâi la C, apoi la nativ ” încetinește performanța de până la două ori în comparație cu compilarea directă a SML în cod nativ din cauza diferențelor semantice dintre SML și C [5] .
Unele compilatoare SML oferă posibilitatea de a profila codul pentru a determina funcțiile care necesită cel mai mult timp procesor (și rezultatul este întotdeauna neașteptat) [73] , după care vă puteți concentra pe optimizarea lor folosind SML, sau le puteți muta în C cod prin FFI .
Fundamentul teoretic al limbajului este calculul lambda tipat polimorf (Sistemul F) , limitat de Let-polimorfism .
„Definiția”„Standardul” oficial al limbii este Definiția , publicată ca o carte . Definiția este formulată în termeni matematici stricti și a dovedit fiabilitatea . Consistența definiției permite unei persoane să verifice corectitudinea programului și să calculeze rezultatul acestuia fără a rula un anumit compilator; dar, pe de altă parte, Definiția necesită un grad înalt de pricepere pentru a înțelege și nu poate servi drept manual de limbă [74] .
Demonstrabilitatea fiabilității nu a venit de la sine - Definiția a fost revizuită de mai multe ori înainte de a vedea lumina zilei. Multe limbi se bazează pe teorii generale, dar în timpul dezvoltării ele nu sunt aproape niciodată testate pentru siguranța partajării unor elemente specifice de limbaj care sunt aplicații speciale ale acestor teorii, ceea ce duce inevitabil la incompatibilitatea între implementările limbajului. Aceste probleme fie sunt ignorate, fie sunt prezentate ca un fenomen natural ( ing. „nu un bug, ci o caracteristică” ), dar în realitate sunt cauzate de faptul că limbajul nu a fost supus analizei matematice [76] .
DetaliiDefiniția originală, „ Definiția standardului ML ”, a fost publicată în 1990 [2] . Un an mai târziu, au fost publicate „Comments on the Definition” („ Commentary on Standard ML ”), explicând abordările și notațiile aplicate [77] . Împreună formează specificația pentru limbajul cunoscut acum ca „ SML'90 ”. În anii următori, au apărut o serie de critici și sugestii de îmbunătățire (una dintre cele mai cunoscute fiind sumele transparente ale lui Harper-Lilybridge ), iar în 1997 multe dintre acestea au fost compilate într-o versiune revizuită a Definiției, „ Definiția de Standard ML: revizuit „ [3] , definind o versiune a limbajului SML'97 care este compatibilă cu primul. Definiția revizuită folosește principiile descrise în Comentariile din 1991, astfel încât cei care intenționează să studieze în detaliu Definiția SML sunt sfătuiți să studieze mai întâi SML'90 și abia apoi SML'97. [78]
De-a lungul timpului, în textul Definiției s-au găsit o serie de ambiguități și omisiuni [79] [80] [81] . Cu toate acestea, ele nu diminuează strictețea Definiției în esență - dovada fiabilității acesteia a fost mecanizată în Twelf [82] . Majoritatea implementărilor se conformează destul de strict cu Definiția, deviând în caracteristicile tehnice - formate binare, FFI etc., precum și în interpretarea locurilor ambigue din Definiție - toate acestea duc la necesitatea unui efort suplimentar (mult mai puțin decât pentru majoritatea celorlalte limbi) pentru a asigura portabilitatea perfectă a programelor SML reale între implementări (programele mici în majoritatea cazurilor nu au probleme de portare).
Definiția SML este un exemplu de semantică operațională structurală ; nu este prima definiție formală a limbajului, ci prima care este înțeleasă fără ambiguitate de către dezvoltatorii de compilatori [83] .
Definiția operează pe obiecte semantice , descriindu -le sensul ( sensul ). În introducere, autorii subliniază că este vorba despre obiecte semantice (care, în funcție de limbajul specific, pot include concepte precum pachet, modul, structură, excepție, canal, tip, procedură, legătură, co-utilizare etc.) și nu sintaxa , definesc o reprezentare conceptuală a unui limbaj de programare și tocmai pe ele ar trebui construită definiția oricărui limbaj [84] .
Conţinut
Conform Definiției, SML este împărțit în trei limbi, construite una peste alta: un strat inferior numit „ Limba principală ” ( Limba principală ), un strat mijlociu numit „ Module ” ( Module ) și un strat superior mic numit „ Programe ” ( Programs ), care este o colecție de definiții de nivel superior ( declarații de nivel superior ).
Definiția include aproximativ 200 de reguli de inferență ( inferență ), scrise sub forma unei fracții obișnuite, unde fraza formalizată ML se află în poziția numărătorului, iar consecința, care poate fi concluzionată dacă fraza este corectă, este în poziția numitorului .
Definiția distinge trei faze principale în limbaj [85] [86] : analiza ( parsing ), dezvoltare ( elaborare ) și evaluare ( evaluare ). Pregătirea se referă la semantică statică; calcul - la dinamic. Dar evaluarea de aici nu trebuie confundată cu execuția ( execuție ): SML este un limbaj bazat pe expresii ( limbajul bazat pe expresii ), iar obținerea unui rezultat din aplicarea unei funcții tuturor argumentelor se numește execuție ( execuție ) și „evaluarea unei funcția” înseamnă construirea ei însăși a unei definiții. De asemenea, trebuie remarcat faptul că suportul pentru curry în limbaj înseamnă că toate funcțiile sunt reprezentate de închideri , iar acest lucru, la rândul său, înseamnă că este incorect să folosiți termenul „apel de funcție”. În loc să apelăm , ar trebui să vorbim despre aplicația funcției ( aplicația funcției ) - pur și simplu funcția nu poate fi apelată până când nu primește toate argumentele; aplicarea parțială a unei funcții înseamnă evaluarea unei noi funcții (o nouă închidere ). Pentru fiecare dintre straturile limbajului (kernel, module, programe), semantica statică și dinamică sunt descrise separat, adică etapele analizei, dezvoltării și calculului.
O anumită implementare a limbajului nu este necesară pentru a face toate aceste distincții, ele sunt doar formale [86] . De fapt, singura implementare care se străduiește să le impună cu strictețe este HaMLet . În special, producția fără evaluare înseamnă noțiunea tradițională de compilare.
Evaluarea fiecărei definiții pe parcursul programului schimbă starea mediului global ( mediu de nivel superior ), numită bază . În mod formal, execuția programului este calculul unei noi baze ca sumă a bazei inițiale și a definițiilor programului. Biblioteca standard în SML este „baza implicită” disponibilă pentru fiecare program de la început și, prin urmare, este numită simplu Baza. Definiția în sine conține doar baza inițială (baza inițială ), care conține definițiile minime necesare; baza mai extinsă a fost standardizată mult mai târziu, suferind o dezvoltare îndelungată în practică .
Semantica Harper-StoneSemantica Harper-Stone ( semantica HS pe scurt ) este o interpretare a SML într-un cadru tipizat . Semantica XC a SML este definită prin dezvoltarea SML-ului extern într-un limbaj intern, care este un calcul lambda tipizat explicit și, astfel, servește drept justificare teoretică a tipului pentru limbaj. Această interpretare poate fi văzută ca o alternativă la Definiție , formalizând „obiecte semantice statice” în termeni de expresii tip lambda-calcul; și, de asemenea, ca o descriere declarativă a regulilor de generare pentru compilatoare direcționate de tip, cum ar fi TILT sau SML/NJ . De fapt, front-end-ul compilatorului TILT întruchipează această semantică, chiar dacă a fost dezvoltat cu câțiva ani mai devreme. [87] [88] [89]
Limbajul intern se bazează pe limbajul XML al lui Harper-Mitchell, dar are un set mai mare de primitive și un sistem de module mai expresiv bazat pe sumele transparente ale lui Harper-Lilybridge . Acest limbaj este potrivit pentru dezvoltarea multor alte limbaje a căror semantică se bazează pe calculul lambda , cum ar fi Haskell și Scheme .
Această abordare este inclusă în proiectul ML succesor . În același timp, schimbările în limbaj care nu afectează limbajul intern sunt considerate ca o perspectivă pe termen scurt ( ing. pe termen scurt ), și necesită schimbări - ca o perspectivă pe termen lung ( ing. pe termen lung ).
Dezvoltatorii SML au stabilit limbajul la cel mai înalt standard de calitate încă de la început, astfel încât pragul de critică este mult mai mare decât majoritatea limbajelor industriale. Mențiuni despre deficiențele limbajului SML se găsesc în presa oficială la fel de des ca și în limbajul C++ și mult mai des decât majoritatea celorlalte limbi, dar motivul nu este deloc o atitudine negativă față de SML - dimpotrivă, orice critica la adresa SML se face cu o atitudine foarte calda fata de acesta. Chiar și o analiză pedantă a deficiențelor SML este de obicei însoțită de descrierea sa ca „o limbă uimitoare, singurul limbaj serios existent ” [90] . Cu alte cuvinte, cercetătorii analizează în detaliu deficiențele, sugerând că, chiar și luând în considerare, SML se dovedește a fi mai preferabil pentru utilizarea în proiecte uriașe de știință intensivă decât multe limbaje mai populare și dorind să aducă SML la perfecțiune.
Avantaje
Defecte
Principala problemă pentru dezvoltatorul SML de astăzi este nivelul slab de dezvoltare a mediului (în special IDE ) și a dezvoltării bibliotecilor.
Securitatea SML înseamnă supraîncărcare pentru aritmetică: datorită cerinței ca fiecare operație să aibă un comportament identic pe fiecare platformă, verificările de depășire , împărțirea la zero etc. sunt componente esențiale ale fiecărei operații aritmetice. Acest lucru face ca limbajul să fie o alegere ineficientă pentru problemele de zdrobire numerică , în special pentru arhitecturile pipeline [91] .
Comparație cu OCaml :
OCaml este cea mai apropiată rudă a SML, despărțindu-se de acesta chiar înainte de standardizare. OCaml este atât de dezvoltat încât uneori este denumit în glumă „ SML++ ”. În programarea de masă, OCaml este semnificativ înaintea SML în popularitate; în cercurile academice, SML este mult mai des obiectul cercetării științifice. Dezvoltatorul principal OCaml, Xavier Leroy, este membru al consiliului ML succesor .
OCaml are o singură implementare care include două compilatoare (la bytecode și la nativ) care sunt aproape identic compatibile și care evoluează constant, oferind nu numai medii mai bune, ci și caracteristici semantice din ce în ce mai puternice. SML are multe implementări diferite care urmează aceeași definiție de limbaj și bibliotecă de bază și, uneori, oferă caracteristici suplimentare.
Cele mai importante diferențe sunt în semantica echivalenței de tip. În primul rând, în SML, functorii sunt generatori, în timp ce în OCaml sunt aplicativi (vezi echivalența tipului în limbajul modulului ML ). În al doilea rând, OCaml nu acceptă variabile de tip egalitate : operația de egalitate acceptă obiecte de orice tip, dar aruncă o excepție dacă sunt incompatibile.
Versiunile moderne ale OCaml includ caracteristici semantice care sunt disponibile numai individual în unele extensii SML, cum ar fi:
Comparație cu Haskell :
Haskell este moștenitorul ML/SML (în acest sens, de obicei nu există nicio diferență fundamentală între ML și SML). Ambele limbi se bazează pe sistemul de tip Hindley-Milner , inclusiv inferența de tip , din care există o mulțime de asemănări [95] ( funcții de primă clasă , polimorfism parametric sigur de tip , tipuri de date algebrice și potrivire de modele pe ele) .
Printre diferențele cheie se numără [95] [96] [97] [98] [99] [68] [100] :
Semantica formală a SML este orientată spre interpretare , cu toate acestea, majoritatea implementărilor sale sunt compilatoare (inclusiv compilatoare interactive ), dintre care unele concurează cu încredere în eficiență cu limbajul C , deoarece limbajul se pretează bine analizei globale. Din același motiv, SML poate fi compilat în cod sursă în alte limbaje de nivel înalt sau mediu - de exemplu, există compilatoare de la SML la C și Ada .
Limbajul se bazează pe o tastare polimorfă statică puternică , care nu numai că asigură verificarea programului în etapa de compilare, ci și separă strict mutabilitatea , ceea ce în sine crește potențialul de optimizare automată a programului - în special, simplifică implementarea colectorului de gunoi [104]. ] .
Prima versiune a ML a fost introdusă în lume în 1974 ca un meta-limbaj pentru construirea de dovezi interactive ca parte a sistemului Edinburgh LCF (Logic for Computable Functions) [2] . A fost implementat de Malcolm Newey, Lockwood Morris și Robin Milner pe platforma DEC10. Prima implementare a fost extrem de ineficientă, deoarece constructele ML au fost traduse în Lisp , care a fost apoi interpretat [105] . Prima descriere completă a ML ca componentă a LCF a fost publicată în 1979 [2] .
În jurul anului 1980, Luca Cardelli a implementat primul compilator Vax ML , adăugând câteva dintre ideile sale la ML. Cardelli a portat în curând Vax ML pe Unix folosind Berkley Pascal. Timpul de rulare a fost rescris în C , dar cea mai mare parte a compilatorului a rămas în Pascal. Munca lui Cardelli l-a inspirat pe Milner să creeze SML ca limbaj de uz general în sine și au început să lucreze împreună în Edinburgh , rezultând compilatorul Edinburgh ML , lansat în 1984. În cursul acestei lucrări, Mike Gordon a venit cu tipuri de referință și le-a propus lui Louis Damas, care mai târziu a făcut disertația sa despre ele [106] . Simultan, Cambridge a colaborat cu INRIA. Gerard Hugh de la INRIA a portat ML la Maclisp sub Multics. INRIA și-a dezvoltat propriul dialect al ML numit Caml, care mai târziu a evoluat în OCaml . Lawrence Paulson a optimizat Edinburgh ML astfel încât codul ML să ruleze de 4-5 ori mai repede. La scurt timp după aceea, David Matthews a dezvoltat limbajul Poly bazat pe ML. Lucrările ulterioare în această direcție au condus la crearea mediului Poly/ML . În 1986, David McQueen a formulat limbajul modulului ML , iar Andrew Appel sa alăturat lucrării Împreună au început să lucreze la compilatorul SML/NJ , care a servit atât ca platformă de cercetare pentru dezvoltarea limbajului, cât și ca primul compilator de optimizare din industrie. Multe dintre implementările limbajului au fost inițial dezvoltate folosind SML/NJ și apoi promovate .
Cu experiența dezvoltării pe scară largă, au fost descoperite o serie de deficiențe în definiția limbajului din 1990 . Unele dintre deficiențe au fost remediate în Revizuirea Definiției din 1997 [3] , dar sfera de aplicare a revizuirii elimină pierderea compatibilității cu înapoi (codurile se adaptează cosmetic, fără a fi nevoie de rescrie de la zero). În 2004, a fost publicată specificația pentru componența Bibliotecii de bază (un proiect al caietului de sarcini datează din 1996 ). Alte deficiențe au fost remediate în alte limbi: ML a generat o întreagă familie de limbi tip X-M . Aceste limbi au câștigat popularitate în sarcina de proiectare a limbajului și sunt adesea definite ca „ DSL -uri pentru semantică denotațională . Cercetătorii care au fost implicați în dezvoltarea și utilizarea SML timp de aproape trei decenii, până la sfârșitul secolului al XX-lea, au format o comunitate pentru a crea un nou limbaj - succesor ML .
De fapt, SML nu a fost primul din familie după LCF/ML în sine - a fost precedat de limbaje precum Cardelli ML și Hope [9] . Francezii își păstrează propriul dialect - Caml / OCaml [12] . Cu toate acestea, când spun „ML”, mulți oameni înseamnă „SML” [107] , și chiar scriu prin fracțiune: „ML/SML” [82] .
Cel mai recomandat manual [108] [109] [110] [111] [112] [113] despre SML este ML for the Working Programmer [107] de Lawrence Paulson (autor al sistemului HOL ) .
Pentru o introducere inițială în limbă, un curs scurt (de câteva zeci de pagini) „ Introducere în Standard ML ” de Robert Harper (disponibil în traducerea rusă [114] ), pe care l-a folosit pentru a preda limba și l-a extins în următorul două decenii până la un manual mai important [115] .
Cartea lui Ricardo Pucella [30] servește ca un tutorial pentru utilizarea bibliotecii standard a limbii, presupunând o cunoaștere de bază a acesteia .
Alte manuale includ cărți de Gilmore [116] , Ullman [117] , Shipman [118] , cartea online a lui Cumming [119] .
Dintre ghidurile de utilizare profesională a limbajului, se poate evidenția cartea lui Andrew Appel (dezvoltatorul principal al SML/NJ ) „ Implementarea compilatorului modern în ML ” [120] (această carte are două surori gemene ). : „ Implementarea compilatorului modern în Java ” și „ Implementarea compilatorului modern în C ”, care sunt echivalente ca structură, dar folosesc alte limbaje pentru a implementa metodele prezentate). Există, de asemenea, multe articole publicate în reviste precum JFP , ML workshop etc. [121] [122]
SML, împreună cu OCaml , servește drept primul limbaj de predare pentru predarea programării în multe universități din întreaga lume. Dintre limbile aplicative , acestea au probabil cel mai scăzut prag de intrare.
O parte semnificativă a codului SML existent este fie o implementare a propriilor compilatoare, fie sisteme automate de demonstrare, cum ar fi HOL , Twelf și Isabelle (sistem automat de demonstrare a teoremei). Toate sunt gratuite și deschise .
Cu toate acestea, există și mai „mundane”, inclusiv produse brevetate [123] .