ML standard

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită la 27 februarie 2022; verificările necesită 3 modificări .
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 ) ( 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 .

Informații generale

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 .

Caracteristici distinctive

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ă .

Caracteristici

Sistem de tip expresiv puternic

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:

Suport pentru programare funcțională Suport pentru programare imperativă Asigurarea unei eficiențe ridicate a programului

Utilizare

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:

Limba

Semantică de bază

Declarații, expresii, blocuri, funcții Tipuri primitive Tipuri compuse și definite Valori modificabile Limitarea valorilor

Restricție de valoare _ _  _

Structuri de control

Programare la scară largă

Modularitate

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:

  • structuri ( structure)
  • semnături ( signature)
  • functori ( functor)

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 ).

Sintaxă și zahăr sintactic

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 withtype

De 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ă . foldr

Desigur, 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ătura

SML 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

Ecosistemul lingvistic

Bibliotecă standard

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 scanere

Schema 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 final

Schema 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 final

Numerele 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 șirGetc

Structura 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.

Portare

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 .

Setul de instrumente de dezvoltare

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
  • SML/NJ (Standard ML of New Jersey) ( articol principal ) [34] este un compilator de optimizare multiplatformă. Suportă REPL și compilare batch. Este implementarea „canonică” a SML, deși are multe abateri de la Definiție [35] ; a servit ca instrument de dezvoltare pentru o serie de alte compilatoare și sisteme automate de verificare . Generează cod nativ pentru un număr mare de arhitecturi și sisteme de operare. FFI se bazează pe generarea de cod dinamic. Oferă o serie de extensii experimentale, dintre care cele mai notabile includ suport pentru continuări de primă clasă , o implementare a CML bazată pe acestea, una dintre implementările modulelor de ordin superior (dar nu de primă clasă ) și o mecanism de cvasi -citare pentru încorporarea limbilor [36] [37] . Însoțit de documentație bogată.
  • MLton (pronunțat „ milton ”) ( articolul principal ) ( site-ul web al proiectului ) este un compilator de optimizare a programului complet multiplatformă. Oferă performanță la nivel C / C++ pentru programele SML prin optimizări agresive, inclusiv extinderea domeniului de aplicare a modulelor, monomorfizarea și defuncționalizarea completă programului și reprezentarea nativă ( neînfășurată și neevaluată) a tipurilor, șirurilor și matricelor primitive; are FFI direct ; pentru aritmetica lungă folosește GnuMP . Generează cod nativ pentru un număr mare de arhitecturi sub sistemul de operare Unix (sub Windows necesită Cygwin sau MinGW ); are back-end-uri în C , C-- , LLVM . Include biblioteca de bază completă (chiar și toate structurile opționale), are propriile porturi pentru multe dintre bibliotecile tipice SML/NJ , inclusiv implementarea continuărilor și CML . FFI oferă apeluri în ambele direcții ( funcții C din codul SML și invers), până la recursiunea reciprocă . Este însoțit de o documentație foarte bogată, inclusiv o descriere a trucurilor cu utilizarea non-trivială a limbajului, permițându-i să fie extins cu idiomuri utile . Dezavantajele, datorate analizei globale și multor pași de transformare, sunt costuri semnificative de timp și memorie pentru muncă.
  • Poly/ML [38] este un compilator de optimizare multiplatformă. Generează un cod destul de rapid, suportă sisteme multiprocesor (pe fire POSIX ), realizează colectarea de gunoi în paralel , asigurând co-utilizarea structurilor de date imuabile; folosește aritmetica lungă în mod implicit (o structură este asociată cu semnătura INTEGERla nivelul superior IntInf). Oferă o interfață directă către WinAPI și sistemul X Window . Implementarea binară vine sub Windows ; sub alte sisteme de operare, trebuie să colectați singur codurile sursă. Generează cod nativ pentru i386 , PowerPC , SPARC , are back-end la bytecode pentru a rula pe platforme neacceptate. Poly/ML este în centrul lui Isabelle (sistem automat de demonstrare a teoremei), împreună cu SML/NJ .
  • ML Kit [39] este un compilator de optimizare completă . Concentrat pe dezvoltarea aplicațiilor în timp real : utilizează o strategie de gestionare a memoriei bazată pe inferența regiunilor statice , permițând colectarea de gunoi în timp constant ; precum și capacitatea non-standard de a opri temporar colectorul de gunoi în jurul secțiunilor critice pentru viteză. Extinde domeniul de aplicare al modulelor - pe lângă îmbunătățirea performanței, acest lucru este important și pentru afișarea regiunilor. Oferă programe de performanță destul de ridicată. Generează cod nativ x86 pentru Windows și Unix , are și backend-uri pentru bytecode și cod JavaScript . Printre deficiențe, se remarcă lipsa suportului pentru concurență și unidirecționalitatea FFI (se asigură apeluri de la SML la C, dar nu invers).
  • SML# (a nu se confunda cu SML.NET ) este un compilator SML de optimizare cu extensii (formând dialectul SML# ). Numele nu trebuie să inducă în eroare, SML# se compilează în cod nativ și nu are legătură cu platforma .NET (SML# a apărut cu câțiva ani mai devreme). Generează cod nativ x86 sub POSIX . Începând cu versiunea 2.0, back-end-ul se bazează pe LLVM , care va extinde și mai mult lista de arhitecturi acceptate. Versiunea 3.0 a introdus suport x86-64 și un colector de gunoi complet simultan pentru a asigura utilizarea eficientă a sistemelor multi-core și fără întreruperi ale programului. Oferă performanțe bune, inclusiv datorită reprezentării native (neînfășurate și neetichetate) a tipurilor primitive și FFI direct către C și SQL ; optimizări mai puternice sunt planificate în viitorul apropiat. Include, de asemenea, un generator de imprimare destul de , un generator de documentație.
  • Manticore [40] este un compilator pentru dialectul Manticore . Generează cod nativ x86-64 pentru Linux și MacOS X. Funcționează în modul REPL .

Verificarea compilatoarelor
  • CakeML [41] este un compilator de încredere dovedit . Implementează un subset semnificativ de ML standard și este auto - scris (inclusiv runtime ). Atât semantica limbajului, cât și algoritmul de compilare sunt descrise prin logica de ordin superior și verificate astfel încât programele CakeML să fie traduse în cod de mașină echivalent din punct de vedere semantic, cu fiabilitate dovedită . Scopul proiectului este de a face din sistemele de dovezi interactive o platformă practică pentru dezvoltarea aplicată. Pentru 2016, generează cod nativ pentru x86-64 , suportul pentru o serie de alte arhitecturi este planificat în viitorul apropiat.
  • TILT , sau TIL-Two ( coduri sursă (Git) ) este un compilator bazat pe ideea de a utiliza exclusiv limbaje intermediare sigure de tip în procesul de compilare ( Typed Intermediate Language , TIL - de unde și numele), până la asamblator tipat , pentru a menține programe de siguranță în toate etapele de transformare și optimizare. Partea frontală a compilatorului se bazează pe semantica Harper-Stone [42] . Dezvoltat de Robert Harper și colegii săi în scopuri de cercetare la mijlocul anilor 1990 și nu a mai fost menținut de atunci.
  • FLINT ( pagina de proiect pe Yale.edu ) este similară cu TILT , dar limbajul intern nu are un calcul de module dedicat, în timp ce limbajul extern acceptă module de ordin superior. FLINT a fost introdus în SML/NJ, ceea ce a crescut performanța acestuia din urmă. [43]

Compilatoare la bytecodes și Java
  • Alice este un compilator SML multiplatformă cu extensii (formând dialectul Alice ) la codul de octeți JIT VM . Axat pe dezvoltarea sistemelor distribuite . Are propriul REPL - IDE cu un inspector încorporat, care permite compilarea fragmentelor de cod selectate (cu condiția ca acestea să fie autosuficiente) și apoi furnizează informații interactive despre tipurile derivate. Compilarea separată este acceptată. Funcționează sub Windows și diferite sisteme asemănătoare Unix . Pe lângă baza standard, oferă o serie de biblioteci suplimentare, are o interfață cu SQLite și Gtk+ . Însoțit de instrucțiuni detaliate pentru utilizarea limbajului furnizat și a extensiilor de bibliotecă (presupunând cunoștințe de SML).
  • Moscow ML [44] este un compilator ușor pentru bytecode . Bazat pe timpul de execuție Caml Light , acceptă REPL și compilarea loturilor. Compilează rapid, dar optimizarea este neglijabilă [45] . Oferă extensii de limbaj ( functor de ordin superior , pachete , cvasi-ghilimele ), are o interfață cu un număr de biblioteci de sistem și multimedia. Dezvoltat în Rusia la Institutul Keldysh sub îndrumarea lui Romanenko A.S. în scopuri educaționale; suportul pentru limbajul modulelor cu extensii a fost implementat de Claudio Russo (autorul semanticii pachetului ).
  • MLj - vezi SML.NET
  • SML.NET [46] - a nu fi confundat cu SML# - compilator de optimizare completă pentru platforma .Net . A apărut din compilatorul MLj pentru platforma JVM . Oferă o interfață pentru conectarea cu alte limbi .NET . Are propriul sistem de analiză a dependenței între module. Compilează numai module întregi, extinzându-și domeniile. Gestionat atât din linia de comandă normală, cât și din modul REPL nativ .
  • SMLtoJs [47] este un compilator pentru codul sursă JavaScript . Efectuează multiple optimizări, inclusiv dezvăluirea domeniului de aplicare a modulelor. Folosește MLton și ML Kit pentru a funcționa .
    • SMLonline [48] este un
    IDE online pentru SMLtoJ care vă permite să lucrați de la distanță dintr-un browser .
  • sml2c [49] este un compilator pentru codul sursă C. Construit pe SML/NJ frontend și runtime și acceptă multe dintre extensiile sale (inclusiv continuări de primă clasă ). Generează cod în ANSI C portabil , dar din cauza diferențelor de proprietăți semantice, dă o încetinire de 70-100% în comparație cu traducerea directă a SML în codul mașină [5] . Funcționează numai cu definiții la nivel de modul în modul lot. Programele la nivel de modul compilate cu SML/NJ pot fi compilate cu SML2c fără modificări. Spre deosebire de SML/NJ , nu acceptă depanarea și crearea de profiluri la nivel de cod sursă.
  • RML-to-3GL este un compilator al limbajului RML (un subset al limbajului SML de a patra generație) în codul sursă în Ada ( limbaj sigur de a treia generație ) [6] . Este similară ca structură cu MLton [50] : folosește monomorfizarea , defuncționalizarea și aplatizarea unui limbaj de ordin superior la un limbaj de ordinul întâi.
  • SML2Java este un compilator pentru codul sursă Java [51] .
  • Implementări de nivel superior
    • HaMLet [52] este implementarea de referință a SML. Reprezintă un interpret pentru o implementare directă, rând cu linie, a limbajului Definiție . Nu este destinat utilizării industriale - extrem de ineficient și oferă mesaje de eroare puțin informative -, în schimb, servește ca o platformă pentru cercetarea limbajului în sine și pentru căutarea posibilelor defecte în Definiție. HaMLet în sine este scris în întregime în SML (25k linii de cod) fără utilizarea C , iar capacitatea unui compilator SML de a asambla coduri HaMLet poate fi văzută ca un semn al unei implementări rezonabil de bune a definiției limbajului și bibliotecii de bază. În special, codurile HaMLet pot compila SML/NJ , MLton , Moscow ML , Poly/ML , Alice , ML Kit , SML# , și, desigur, el însuși. HaMLet are, de asemenea, un mod „ HamLet S ”, care este implementarea de referință a versiunii curente a succesorului ML (sML) . Proiectat și întreținut de Andreas Rossberg.
    • Isabelle/ML [53] este un LCF - componenta de stil a lui Isabelle ( sistemul de demonstrare a teoremei ) . Isabelle a fost dezvoltată sub conducerea lui Luca Cardelli pe baza sistemului HOL-90 . Include un editor bazat pe jEdit . Cea mai semnificativă componentă a lui Isabelle este Isabelle/HOL , care, pe baza specificațiilor executabile, vă permite să generați coduri sursă SML, OCaml , Haskell , Scala , precum și documentație bazată pe inserții L A Τ Ε Χ în codul sursă.
    • Edinburgh LCF (Logic for Computable Functions) ( articolul principal ) (codurile sursă sunt disponibile ca parte a Isabelle ) - un sistem interactiv de demonstrare a teoremei , din punct de vedere istoric prima implementare a limbajului rădăcină ML (înainte de introducerea limbajului modulului și formarea LMS).

    Implementări învechite
    • Poplog [54] este un compilator incremental și un mediu de dezvoltare integrat axat pe lucrul în domeniul inteligenței artificiale . Oferă posibilitatea de a amesteca mai multe limbi în același timp, inclusiv POP-11 , Prolog , Common Lisp și SML. Reprezentarea internă a tuturor limbilor se bazează pe POP-11 - Lispo - ca limbaj reflexiv ; Poplog însuși este implementat pe el. Include un editor asemănător Emacs și suport pentru GUI , dar numai sub sistemul X Window ; sub Windows oferă doar o consolă. Numele Poplog este un acronim pentru „POP-11” și „Prolog”. În ciuda faptului că Poplog este dezvoltat activ, a rămas în urmă cu dezvoltarea limbajului SML: în prezent, implementarea sa SML nu este conformă cu definiția actuală ( SML'97 ) și nu implementează Biblioteca de bază.
    • MLWorks [55] este un compilator cu un IDE complet și instrumente aferente. Anterior comercial, dezvoltat de Harlequin în anii 1990 . La începutul secolului, proprietarul s-a schimbat și sprijinul a fost întrerupt. În 2013, și-a găsit un nou proprietar, care a deschis codurile sursă și a organizat munca la resuscitarea proiectului. Nu este operațional din 2016 .
    • Edinburgh ML ( coduri sursă ) este un compilator ML nedeformat bazat pe primul compilator ML din punct de vedere istoric dezvoltat de Luca Cardelli Vax ML (a doua implementare a ML după Edinburgh LCF (Logic for Computable Functions) ). Codurile sunt acum open source, dar din moment ce nu s-au schimbat din anii 1980 , ele încă afirmă că ML nu este în domeniul public și utilizarea acestui compilator necesită licențiere.
    • TILT - vezi Verificarea compilatoarelor

    Dialecte, extensii

    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.

    Alice

    Alice 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 concurent

    Concurrent 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] .

    Manticore

    Manticore [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 .

    MLPolyR

    MLPolyR  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 .

    Mythryl

    Mythryl [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

    Utilități

    • Compilation Manager (CM) și MLBasis System (MLB)  sunt extensii ale compilatorului pentru a sprijini mai bine modularitatea (controlul dependenței). În principiu, make , tradițional pentru majoritatea limbilor, ar putea fi folosit și în acest scop , dar limbajul modulului SML este mult mai puternic decât instrumentele de modularizare ale altor limbi și make nu își susține avantajele și nu este potrivit pentru a lucra în Modul REPL [59] . CM a fost implementat inițial în SML/NJ , apoi portat la MLton . Ulterior, ca parte a MLton , au fost propuse sistemul MLB și convertorul de fișiere .cm în .mlb . Suportul MLB a fost adăugat la Kitul ML .
    • eXene [60] este o  bibliotecă GUI pentru sistemul X Window . Implementează un model de interacțiune reactiv bazat pe CML . Furnizat cu SML/NJ .
    • MLLex , MLYacc , MLAntlr , MLLPT sunt  generatoare de lexer și parser (vezi Lex și Yacc ).

    Interacțiune interlingvistică

    • FFI (Foreign Function Interface -Russian interface to foreign functions) - legături încrucișate . În diferite compilatoare, are o implementare diferită, care este strâns legată de reprezentarea datelor (în primul rând, înfășurate sau dezlegate, etichetate sau neetichetate). În SML/NJ, FFI se bazează pe generarea de cod dinamic, iar dacă o funcție ia un total de octeți ca intrarenși returneazămun octet, atunci apelul său arecomplexitate n+m [61] . Unele compilatoare (MLton ,SML# ) folosesc reprezentarea datelor neîncărcate și fără etichetă și oferă apeluri directe la funcții și date C. În acest din urmă caz, introducerea de funcții lente în codul C poate crește semnificativ performanța generală a programului [62] .
    • NLFFI (No-Longer-Foreign Function Interface - Russian interface to now-no-more-foreign functions ) [63]  - o interfață alternativă, de nivel superior , a funcțiilor externe . NLFFI generează automat codul glue, permițând *.h-fișierelor ( fișiere antet C ) să fie incluse direct într-un proiect SML (CM sau MLB ), eliminând necesitatea codării manuale a definițiilor FFI . Din punct de vedere structural, ideea NLFFI este de a modela sistemul de tip C cu tipuri ML; implementarea se bazează pe CKit . Furnizat cu SML/NJ și MLton .
    • CKit este un limbaj C  front-end scris în SML. Efectuează traducerea codurilor sursă C (inclusiv preprocesor) în AST , implementată folosind structuri de date SML. Stă la baza implementării NLFFI .

    Ideomatică, convenții

    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:

    • preferință pentru un pas de indentare de trei caractere (nu patru)
    • utilizarea frecventă a apostrofului în identificatori (similar cu cel adoptat în matematică): dacă xdoriți să construiți un „ nou x ” pe bază, atunci în majoritatea limbilor se scrie „ x1”, iar în SML, ca în matematică, adesea „ x'” (“ x-stroke ”).
    • sintaxa operațiilor logice binare „ȘI” și „SAU”: andalsoși orelse, respectiv. [66]
    • sintaxa șirurilor infixe și a operațiilor de concatenare a listelor: ^și @, respectiv, (nu sunt furnizate pentru vectori și tablouri).
    Proceduri

    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 se termine D în E fun foo ... = let val _ = ... in ... end

    Tehnici

    Această extensie -

    Această 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 tipuri

    Valori 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.

    Principiu

    Este 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 ) final

    O 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

    Exemple de programe

    Salut Lume!

    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şit

    O 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] .

    Aspect automat

    fun firstLine s = let val ( nume , rest ) = Subșir . splitl ( fn c => c <> #"." ) ( Subșir . full s ) în " \n <P><EM>" ^ Subșir . nume șir ^ "</EM>" ^ Subșir . sfârşitul de odihnă a coardei fun htmlCvt fileName = let val is = TextIO . openIn fileName și os = TextIO . openOut ( fileName ^ ".html" ) fun cvt _ NONE = () | cvt _ ( SOME " \ n " ) = cvt true ( TextIO . inputLine este ) | cvt first ( SOME s ) = ( TextIO . output ( os , if first then firstLine s else "<br>" ^ s ); cvt false ( TextIO . inputLine is ) ) in cvt true ( SOME " \n " ); text . closeIn este ; text . closeOut os end

    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.

    Arbori ternari

    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 => n

    Acest 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 MARE

    Despre limba

    Performanță

    Avantajele 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 .

    Rațiune pentru semantică

    Informații generale

    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] .

    Detalii

    Definiț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-Stone

    Semantica 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 ).

    Critică și comparație cu alternative

    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

    [74] [9] [90] [24]

    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 :

    [92] [93] [94]

    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] :

    Istorie, filozofie, terminologie

    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] .

    Explorând

    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]

    Aplicație

    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] .

    Note

    1. SML'84, 1984 .
    2. 1 2 3 4 SML'90, 1990 .
    3. 1 2 3 SML'97, 1997 .
    4. SML'90, 1990 , E. Anexă: Dezvoltarea ML, p. 81-83.
    5. 1 2 3 Tarditi et al, „No Assembly Required”, 1990 .
    6. 1 2 Tolmach, Oliva, „De la ML la Ada”, 1993 .
    7. 1 2 Comentariu la SML, 1991 , p. v.
    8. 1 2 Pucella, „Notes on SML/NJ”, 2001 , p. unu.
    9. 1 2 3 4 MacQueen, „Reflecții asupra SML”, 1992 .
    10. Descrierea StandardML în ghidul compilatorului MLton . Preluat la 14 august 2016. Arhivat din original la 25 august 2016.
    11. 1 2 ML2000 Preliminary Design, 1999 .
    12. 1 2 Paulson, „ML for the Working Programmer”, 1996 , p. 12.
    13. Paulson, „ML for the Working Programmer”, 1996 , p. 2.
    14. Rossberg, „1ML”, 2015 .
    15. Harper-Stone '99, 1999 .
    16. 1 2 Paulson, „ML for the Working Programmer”, 1996 , 4.13 Structuri de date bazate pe arbore, p. 148-149.
    17. 12 OOP în SML .
    18. MacQueen, „Reflecții asupra SML”, 1992 , p. 2.
    19. Comentariu la SML, 1991 , p. cincisprezece.
    20. Paulson, „ML for the Working Programmer”, 1996 , Imperative Programming in ML, p. 313.
    21. MacQueen, „Reflecții asupra SML”, 1992 , p. 3.
    22. Paulson, „ML for the Working Programmer”, 1996 , p. unu.
    23. 1 2 Appel, „A Critique of Standard ML”, 1992 , Lack of macros, p. 9.
    24. 1 2 VandenBerghe, „Why ML/OCaml are good for writing compilers”, 1998 .
    25. Paulson, „ML for the Working Programmer”, 1996 , 7.8 Testing the queue structures, p. 274.
    26. MacQueen, „Reflecții asupra SML”, 1992 , p. 6.
    27. 1 2 Paulson, „ML for the Working Programmer”, 1996 , 2.3 Identificatori în Standard ML, p. 21.
    28. Paulson, „ML for the Working Programmer”, 1996 , p. 13.
    29. SML Basis, 2004 .
    30. 1 2 Pucella, „Notes on SML/NJ”, 2001 .
    31. Pucella, „Notes on SML/NJ”, 2001 , 4.3. Mai multe despre șiruri, p. 89-92.
    32. Pucella, „Notes on SML/NJ”, 2001 , 4.3. Mai multe despre șiruri, p. 90.
    33. 1 2 Portabilitate ML standard .
    34. Site-ul web al proiectului SML/NJ . Preluat la 14 august 2016. Arhivat din original la 1 mai 2020.
    35. Abateri ale SML/NJ de la Definiția SML'97 (revizuită) . Preluat la 14 august 2016. Arhivat din original la 4 aprilie 2016.
    36. SML/NJ: Încorporarea limbajului obiect cu citat/antiquote . Preluat la 14 august 2016. Arhivat din original la 19 iunie 2016.
    37. Slind, „Language embedding in SML/NJ”, 1991 .
    38. Site-ul web al proiectului Poly/ML Arhivat 27 iunie 2020 la Wayback Machine
    39. Site-ul proiectului ML Kit (link inaccesibil) . Preluat la 14 august 2016. Arhivat din original la 19 iulie 2016. 
    40. 1 2 Site-ul web al Proiectului Manticore . Preluat la 14 august 2016. Arhivat din original la 8 august 2016.
    41. Site-ul proiectului CakeML . Preluat la 14 august 2016. Arhivat din original la 14 septembrie 2020.
    42. conferința sml-evolution: Rober Harper, 30.10.2006.
    43. Shao, „FLINT/ML Compiler”, 1997 .
    44. site-ul web al proiectului MoscowML . Preluat la 14 august 2016. Arhivat din original la 11 ianuarie 2016.
    45. 12 MLton Performance .
    46. Site-ul proiectului SML.NET . Preluat la 14 august 2016. Arhivat din original la 29 ianuarie 2016.
    47. Site-ul proiectului SMLtoJs (downlink) . Preluat la 14 august 2016. Arhivat din original la 14 septembrie 2016. 
    48. Pagina SMonline (link în jos) . Preluat la 14 august 2016. Arhivat din original la 2 octombrie 2016. 
    49. coduri sursă sml2c . Preluat la 14 august 2016. Arhivat din original la 28 august 2018.
    50. De la ML la Ada - descriere în ghidul compilatorului MLton (downlink) . Preluat la 16 septembrie 2016. Arhivat din original la 23 septembrie 2016. 
    51. Koser, Larsen, Vaughan, „SML2Java”, 2003 .
    52. Site-ul proiectului HaMLet . Preluat la 14 august 2016. Arhivat din original la 14 octombrie 2016.
    53. Site-ul proiectului Isabelle/ML . Preluat la 26 august 2016. Arhivat din original la 30 august 2020.
    54. Site-ul web al proiectului Poplog . Preluat la 26 august 2016. Arhivat din original la 18 august 2016.
    55. Proiect ML standard pe GitHub
    56. Site-ul web al proiectului SML# . Preluat la 14 august 2016. Arhivat din original la 8 iunie 2020.
    57. Site-ul proiectului Mythril . Preluat la 14 august 2016. Arhivat din original la 28 iunie 2009.
    58. ^ Taha et al, „Macros as Multi-Stage Computations”, 2001 .
    59. Pucella, „Notes on SML/NJ”, 2001 , Capitolul 6. The Compilation Manager, p. 157.
    60. eXene - set de instrumente X Window System cu mai multe fire scrise în ConcurrentML . Preluat la 14 august 2016. Arhivat din original la 22 februarie 2012.
    61. ^ Huelsbergen , „Interfață C portabilă pentru SML”, 1996 .
    62. Chris Cannam, „De ce a fost OCaml mai rapid?” .
    63. Blume, „No-Longer-Foreign”, 2001 .
    64. Ghid de stil ML standard (din ghidul MLton) . Preluat la 14 august 2016. Arhivat din original la 27 august 2016.
    65. Appel, „A Critique of Standard ML”, 1992 , Constructori greșiți, p. 12.
    66. Harper, „Intro to SML”, 1986 , p. 5.
    67. Tehnica „EtaExpansion” (din Ghidul MLton) . Consultat la 6 septembrie 2016. Arhivat din original pe 10 septembrie 2016.
    68. 1 2 Peyton-Jones, „Retrospective on Haskell”, 2003 .
    69. Valori indexate de tip (din Ghidul MLton) . Preluat la 26 august 2016. Arhivat din original la 21 aprilie 2016.
    70. Tehnica „Fold” (din Ghidul MLton) . Preluat la 24 august 2016. Arhivat din original la 26 septembrie 2016.
    71. Shipman, „Unix Programming with SML”, 2001 , p. 31.
    72. Paulson, „ML for the Working Programmer”, 1996 , 8.9 Exemple de procesare a textului, p. 348-350.
    73. 1 2 Paulson, „ML for the Working Programmer”, 1996 , 1.5 Eficiența programării funcționale, p. 9.
    74. 1 2 3 Appel, „A Critique of Standard ML”, 1992 .
    75. Paulson, „ML for the Working Programmer”, 1996 , p. 108.
    76. Comentariu la SML, 1991 , Scopurile Comentariului, p. vii.
    77. Comentariu la SML, 1991 .
    78. despre Definiția ML standard în ghidul MLton  (link în jos)
    79. Kahrs, 1993 .
    80. Kahrs, 1996 .
    81. Defecte în SML (din manualul HaMLet) . Preluat la 6 septembrie 2016. Arhivat din original la 4 mai 2016.
    82. 12 sml-family.org . _
    83. Paulson, „ML for the Working Programmer”, 1996 , 1.9 ML and the working programmer, p. 16.
    84. SML'90, 1990 , p. v.
    85. SML'90, 1990 , p. unu.
    86. 1 2 Comentariu la SML, 1991 , p. 1-3.
    87. Harper-Stone '96, 1996 .
    88. Harper-Stone '97, 1997 .
    89. Harper-Stone '99, 1999 , p. 1-2.
    90. 1 2 Rossberg, „Defects in SML Revised”, 2001 .
    91. Harper, „Programming in SML”, 2005 , 12.1.1 Primitive Exceptions, p. 104.
    92. Chris Cannam, „Four MLs (and a Python)” .
    93. Chlipala, „OCaml vs. SML” .
    94. Olsson, Rossberg, „SML vs. OCaml” .
    95. 1 2 Shaw, „ML vs. Haskell”, 2012 .
    96. Dreyer, Harper, „Modular Type Classes”, 2007 .
    97. Yallop, White, „Lightweight higher-kinded polymorphism”, 2014 .
    98. 1 2 Augustsson, „Aventura eșuată în Haskell Abstraction” .
    99. ^ Wehr , Chakravarty, „Module vs. Type Classes”, 2008 .
    100. Harper, „Desigur că ML are monade!” .
    101. Paulson, „ML for the Working Programmer”, 1996 , Sequences, or infinite lists, p. 191-201.
    102. Comentariu la SML, 1991 , 3 Semantică dinamică pentru module, p. 26.
    103. Rossberg, „1ML”, 2015 , p. 2.
    104. Appel, „A Critique of Standard ML”, 1992 , Eficiență, p. 7-8.
    105. Paulson, „ML for the Working Programmer”, 1996 , p. unsprezece.
    106. MacQueen, „Cardelli and Early Evolution of ML”, 2014 , p. patru.
    107. 1 2 Paulson, „ML for the Working Programmer”, 1996 .
    108. Cărți recomandate pe pagina compilatorului SML/NJ . Preluat la 26 august 2016. Arhivat din original la 19 august 2016.
    109. Gilmore, "Programming in SML. Tutorial Introduction", 1997 , p. 3.
    110. Shipman, „Unix Programming with SML”, 2001 , p. 455.
    111. MacQueen, „Reflecții asupra SML”, 1992 , p. unu.
    112. Pucella, „Notes on SML/NJ”, 2001 , p. 42.
    113. Baza SML pe cărțile legate de Cambridge University Press . Preluat la 19 mai 2022. Arhivat din original la 24 februarie 2021.
    114. Harper, „Intro to SML”, 1986 .
    115. ^ Harper, „Programarea în SML”, 2005 .
    116. Gilmore, „Programming in SML. Tutorial Introduction”, 1997 .
    117. Ullman, „Elementele de programare ML”, 1998 .
    118. ^ Shipman, „Unix Programming with SML”, 2001 .
    119. Cumming, 1995 .
    120. Appel, „Implementarea compilatorului modern în ML”, 1998 .
    121. Fluet, Pucella, „Tipuri fantomă și subtipări”, 2006 .
    122. Pucella, „Programarea reactivă în SML”, 2004 .
    123. Utilizatori ML standard . Preluat la 14 august 2016. Arhivat din original la 10 septembrie 2016.

    Literatură

    Standarde

    Tutoriale, ghiduri, cărți de referință, utilizare

    • Robert Harper Introducere în Standard ML. - Universitatea Carnegie Mellon, 1986. - 97 p. — ISBN PA 15213-3891.
    • Konrad Slind. Încorporarea limbajului obiect în Standard ML din New Jersey. - Proceedings of the 2nd ML workshop, Carnegie Mellon University., 1991.
    • Lawrence C. Paulson . ML pentru programatorul de lucru. — al 2-lea. - Cambridge, Marea Britanie: Cambridge University Press, 1996. - 492 p. -ISBN 0-521-57050-6(copertă cartonată), 0-521-56543-X (copertă moale).
    • Jeffrey Ullman. Elemente de programare ML  . - Prentice-Hall, 1998. - ISBN 0-13-790387-1 .
    • Andrew W. Appel. Implementarea modernă a compilatorului în ML  . - Cambridge, Marea Britanie: Cambridge University Press, 1998. - 538 p. - ISBN 0-521-58274-1 (copertă cartonată), 0-521-60764-7 (copertă cartonată).
    • Anthony L. Shipman. Programarea sistemului Unix cu  ML standard . — 2001.
    • Riccardo Pucella. Note privind programarea Standardului ML din New  Jersey . - Ultima revizuire 10 ianuarie 2001. - Universitatea Cornell, 2001.
    • Bernard Berthomieu. Stiluri de programare OO în ML . — Raportul LAAS #2000111, Centre National De La Recherche Scientifique Laboratoire d'Analyse et d'Architecture des Systèmes, 2000.
    • Riccardo R. Pucella. Programare reactivă în ML standard  . — Bell Laboratories, Lucent Technologies, 2004.

    Istorie, analiză, critică

    • Milner , Morris, Newey. O logică pentru funcții calculabile cu tipuri reflexive și polimorfe // Arc-et-Senans. — Proc. Conferința privind demonstrarea și îmbunătățirea programelor, 1975.
    • Gordon, Milner , Morris, Newey, Wadsworth. Un metalanj pentru demonstrarea interactivă în LCF. — 1977.
    • David McQueen. Structuri și parametrizare într-un limbaj funcțional tipizat. — 1981.
    • Stefan Kahrs. Greșeli și ambiguități în definiția ML-  Anexe standard . - Universitatea din Edinburgh, 1996.  (link inaccesibil)
    • Robert Harper , Christopher A. Stone. Un raport teoretic de tip al Standardului ML // Raport tehnic CMU-CS-96-136R. — Universitatea Carnegie Mellon, 1996.
    • Robert Harper , Christopher A. Stone. O interpretare a standardului ML în teoria tipurilor // Raport tehnic CMU-CS-97-147. — Universitatea Carnegie Mellon, 1997.
    • Andreas Rossberg, Claudio Russo, Derek Dreyer. Module F-ing  . — TLDI, 2010.

    Diverse

    • Derek Dreyer, Robert Harper . Clase de tip  modular . — ACM SIGPLAN, 2007.

    Link -uri