LML Estàndard, conegut per les sigles SML, de l'anglès Standard ML, és un llenguatge de programació funcional per a aplicacions de tota mena, amb comprovació de tipus en temps de compilació, i inferència de tipus.
És popular entre desenvolupadors de compiladors, i investigadors de llenguatges de programació, així com demostradors de teoremes.
SML és un descendent modern del llenguatge de programació ML emprat en el projecte de demostració de teoremes "Lògica per a funcions computables".
Es distingeix entre altres llenguatges de programació en què té una especificació formal i semàntica operacional proposades a "La Definició de Standard ML (1990)" i revisada i simplificada en l'edició de 1997.
Programa "Hola Món" Podem descarregar l'intèrpret sml de SML de New Jersey cas de Linux, del paquet smlnj altrament el podeu descarregar d'aquí.SML de New Jersey Instruccions per a l'intèrpretSmlNJ Interactiu la grafia de l'apuntador (el text que l'intèrpret escriu per indicar que espera l'entrada) normal de l'intèrpret és '-'. Si la comanda és incompleta (ex. ens hem deixat el punt i coma final) canvia a '=' Per carregar un fitxer sml la comanda és: use "nomfitxer" ;
$sml - val run = print "Hola Món\n" ;
Hola Món val run = () : unit
També podem obtenir els compiladors MLtonCompilador MLton i MLkit.Compilador MLkit
Característiques Vegeu ref.StandardML
Generals Avaluació primerenca (Semàntica estricta). Les expressions s'avaluen i associen als símbols lligats seguint l'ordre de les declaracions.
Identificadors Vegeu ref.SML identifiers
Sintaxi Vegeu enllaç.Univ. Edimburg - Sintaxi de SML Les instruccions, excepte la darrera, se separen amb punt i coma. Els punt i coma a fi de línia es poden estalviar.
Per especificar més d'una instrucció en una expressió (per ex. prints, o assignacions, a més de l'expressió de retorn) cal no ometre els punt-i-coma de separació.
val nom = let val a = expr1 val b = expr2 in expr3; expr4; expr_a_retornar end
Comentaris (* comentari multilínia *)
Tipus Tipus bàsics Consulteu-ne les operacions a la biblioteca SML Basis
unit (* tipus buit *) literals: ()
bool (estructura Bool) literals: true, false ops: not b a orelse b a andalso b
int (estruct. Int), LargeInt.int (* sencers (consulteu Int.precision i LargeInt.precision a la vostra implementació) Vegeu secció , atenció: el signe menys de l'oper. unària (un sol operand) es fa amb la tilde (tecles AltGr+4 seguit d'espai), no amb el guió, reservat per a la oper. binària *) literals: 0, ~1, (5-4), 0x7F
word (estruct. Word), Word8.word (word8), LargeWord.word (* ops. de naturals amb aritmètica modular , implementa les operacions a nivell de bit , consulteu precisions amb ([Large]Word.fromInt ~1) , opcionalment hi pot haver Word<N>.word (word<N> per abreujar) , els intercanvis entre tipus de dif. precisió es poden fer passant pel tipus LargeWord *) literals: 0w0, 0w1, 0wx7F ops de conversió: Word<N>.{ toLarge | toLargeX (amb extensió de signe) | fromLarge | toInt | ... } algunes op. binàries Word<N>.{andb | orb | xorb | << | >> | ~>> | + | - | * | div | mod | ...} (a, b) (* no hi ha defs infix *) algunes op. unàries Word<N>.{~ (complement a dos) | notb (negació bit a bit) }
real (estruct Real), LargeReal.real (* reals de coma flotant (consulteu Real.precision i LargeReal.precision: són idèntiques en algunes implementacions *) literals: 0.5 ~1.5 (* els reals no es consideren un tipus que implementi igualtat. (a = b) no està definit, tampoc es pot emprar en un "case expr_real of" cal utilitzar Real.== en posició prefix *) Real.== (x, 2.5) (* igualtat excepte si són NaNs (no-numèrics) *) Real.!= (* no Real.==) Real.?= (* igualtat bit a bit, sense tenir en compte el signe del zero *)
char (estruct. Char) literals: #"A" (* caràcter A *)
Tipus algebraics Tipus producte tuples: 'a * 'b * ...
literals: (a, b) (a, b, c) tipus de (5, 3.2) és: int * real tipus de (5, [3.2]) és : int * real list #1 (a, b) = a (* #1: primer elem. o camp *) #2 (a, b) = b
registres: tipus (exemple): {marca: string, rodes: int}
valor: val cotxe_de_l_avi = {marca = "hispano_suiza", rodes = 4}
camp: val marca_del_cotxe = #marca cotxe_de_l_avi
enumeracions datatype color = Vermell | Blau | Verd
Tipus suma (unió discriminada) datatype arbre_sencers = Fulla of int | Branca_sencers of int * arbre_sencers * arbre_sencers ;
val a = Fulla 3 ; val b = Branca_sencers (5, a, a) ;
Tipus polimòrfics Tipus parametritzats. Cas de prefix
un apòstrof: com ('a) indica variable de tipus doble apòstrof: com (''a) afegeix requeriment que la variable implementi igualtat (per a tipus eqtype)
datatype 'a arbre = Arbre_buit | Branca of 'a * 'a arbre * 'a arbre ;
(* cas de més d'un paràmetre, es posen en tupla *) datatype ('a, 'b) un_o_altre = Esquerra of 'a | Dreta of 'b ;
tipus ('a option) per a paràmetres opcionals i com a resultat de funcions definides parcialment:
'a option (estruct. [http://sml.sourceforge.net/Basis/option.html Option]) datatype 'a option = NONE | SOME of 'a ús: case expr of NONE => ... (* cas de no definit *) SOME v => f(v) (* cas definit *)
Llistes 'a list (estruct. [http://sml.sourceforge.net/Basis/list.html List]) datatype 'a list = nil | :: of 'a * 'a list (* nil | ''Cons'' de ('a * llista de 'a) *)
literals: nil, [], [1,2,3] [] = nil ; [ 1, 2, 3] = 1 :: 2 :: 3 :: nil ; ops: 1 :: [2, 3] = [1, 2, 3] [ 1, 2] @ [3, 4] = [1, 2, 3, 4] ; hd [1, 2, 3] = 1 ; tl [1, 2, 3] = [2, 3] ;
(* ops. sobre parelles de llistes a [http://sml.sourceforge.net/Basis/list-pair.html ListPair] *)
Tipus amb allotjament lineal string (estruct. String) literals: "abc" "abc" ^ "def" = "abcdef" String.sub("abc", 0) = #"a" (* subelement (caràcter) a la posició x *) String.str(#"a") = "a" (* caràcter a string *)
(* ops. sobre subseqüències a l'estructura Substring *)
vectors immutables: 'a vector (estruct. Vector) (* seqüència immutable d'accés aleatori (cost O(1)) *)
(* ops. sobre subseqüències a l'estructura VectorSlice *)
vectors mudables: 'a array (estruct. Array) (* seqüència mudable d'accés aleatori (cost O(1)) *)
(* ops. sobre subseqüències a l'estructura ArraySlice *)
Sinònims de tipus type nom_de_tipus; (* tipus abstracte *)
type arbre_de_tires = string arbre
clàusula eqtype t: estableix que el tipus implementa igualtat El símbol = està sobrecarregat per les operacions d'igualtat de diversos tipus, però no tots els tipus l'implementen.Igualtat polimòrfica
En els patrons només es poden emprar literals de tipus que implementin igualtat.
Els Reals no es considera que implementen igualtat. Tenen una operació de comparació específica amb doble signe igual (==) igualtat exceptuant NaNs (no-numèrics); (!=): negat de (==); (?=): igualtat bit a bit sense tenir en compte el signe quan és zero.
Els Arrays tenen una igualtat especial (igualtat de referències), són iguals només si són el mateix (creats en la mateixa crida).
eqtype tipus_eq (* tipus que implementa igualtat *)Equality type ops: (a = b) (* en un case, el tipus de l'expressió i dels patrons que es comparen han de ser eqtype *) (case expr of patró1 => expr1 | patró2 => expr2 | ...)
Per explicitar el requeriment que un tipus implementi igualtat, les operacions polimòrfiques que fan servir igualtat sobre alguns dels paràmetres, han de distingir-ne els paràmetres de tipus mitjançant el prefix de doble apòstrof.Equality type variable
fun cerca (llista: ’’a list, y: ’’a) = (* doble apòstrof degut a (x=y) *) (case llista of nil => false | x::xs => (x=y) orelse cerca (xs, y) )
Restricció de tipus val a : <tipus>
Expressions Lligams Associació d'un símbol a una expressió val v_a = <expressió>
val (v_a, v_b) = <expressió_que_retorna_tupla2>
val {camp_a = v_a, camp_b = v_b} = <expressio que retorna registre amb camp_a i camp_b>
Operadors Vegeu ref.Precedència dels operadors
Alternatives if <condició> then <expressió> else <expressió>
case <expressió> of <patró> => <expressió> | <patró> => <expressió>
Funcions fun incr n = n +1 ;
(* equivalent: lligam d'un símbol amb una funció anònima *) val incr = fn n => n +1 ;
(* amb recursivitat *) val rec fact_rf = fn (acum, 0) => acum | (acum, n) => fact_rf (acum * n, n-1) ;
(* amb restricció / declaració de tipus *) val fact : int -> int = fn 0 => 1 | n => if n > 0 then fact_rf (1, n) else raise Fail "arg. il·legal" ;
(* definicions simultànies (''and'') relacionades circularment *) fun parell 0 = true | parell n = senar (n-1) and senar 0 = false | senar n = parell (n-1)
(* retornant més d'un valor *) fun meitat_i_doble(x:int):int*int = (x div 2, 2*x) ;
Funcions Currificables Vegeu currificació.
fun suma_curri (x:int) (y:int) = x + y; (* tipus suma_curri: int -> int -> int *) fun suma_tupla (x:int, y:int) = x + y; (* tipus suma_tupla: int * int -> int *)
val suma3 = suma_curri 3; (* tipus suma3 : int -> int *) val result = suma3 7; (* aplica suma3 a 7 *)
(* funcions curry i uncurry permeten aplicar funcions a paràmetres agrupats / desagrupats de manera diferent a la definida i en el cas de curry per a poder definir funcions fixant una part dels paràmetres *) fun curry f x y = f (x, y) fun uncurry f (x, y) = f x y
(curry suma_tupla) 3 4; (* aplica func de tupla a params. desagrupats *) val suma_amb3_currificada = (curry suma_tupla) 3 ;
(uncurry suma_curri) (3, 4); (* aplica func de params en seqüència a una tupla *)
Composició de funcions fun aplica_comp f g x = (f o g) x; (* (f . g) operador estàndard lletra 'o' *)
definició d'operadors val << = Word.<< (* declara l'op. << per a l'ús en l'àmbit actual *) infix 5 << (* permet la posició infix de l'operació amb la precedència especificada. ''infixr'' cas d'associativitat per la dreta *)
(* (op <<) ''op'' permet referirnos a l'operador com a funció, i evitar que l'analitzador sintàctic doni error a (<<) per no haver-lo posat en posició infix *)
(op <<): word * word -> word
declaracions d'àmbit local dins d'una expressió let val a = <expressió> in a+1 end
declaracions d'àmbit local a nivell de declaracions local fun incr n = n+1 in val a = incr 5 end
encaixos de patrons '_' és el comodí
fun llargada nil = 0 | llargada (_::cua) = 1 + llargada cua ;
as patterns: v com <patró> fun prova (v as (_::_)) = ... (* la variable v contindrà el terme encaixat *)
encaix de registres fun admet_cotxe ({marca = v_marca, data_fabric = v_data_fabric}) = ...
excepcions (expr) handle Excepció1 => expr1 | Excepció2 => expr2
ex.: exception ExcNo_hi_es of string ;
fun cerca' (str, nil) = raise ExcNo_hi_es (str ^ " no hi és") | cerca' (str, cap::cua) = if str = cap then print (str ^ " trobada\n") else cerca' (str, cua)
fun cerca (str: string, dades: string list) = (cerca' (str, dades); true) handle ExcNo_hi_es msg => (print ("ExcNo_hi_es: " ^ msg ^ "\n"); false) | _ => (print "altra excepció\n"; false)
Mòduls el tipus d'una estructura: Signatura Col·lecció d'especificacions (type, datatype, exception i tipus de variables). signature SigConjunt = sig type ''a conj (* conjunt d'elements de tipus ''a, doble apòstrof: requeriment que implementi igualtat *) val conjunt_buit : ''a conj exception ExcNo_hi_es val afegir_a_conjunt: ''a * ''a conj -> ''a conj val membre_de_conjunt : ''a * ''a set -> bool end
herència en signatures especialització afegint funcions signature SigConjunt_amb_EsBuit = sig include SigConjunt val es_buit: ''a conj -> bool end
especialització per refinament de tipus signature SigConjunt_Com_A_Llista = SigConjunt where type ''a conj = ''a list ;
estructures structure Conjunt = struct type 'a conj = 'a list ; val conjunt_buit = [] ; exception ExcNo_hi_es of string ; val afegir_a_conjunt (x, conj) = op :: ; val membre_de_conjunt = ListUtils.member ; end