Clean
Clean és un llenguatge de programació funcional pur, de semàntica no estricta (avaluació tardana: les expressions s'avaluen només quan se'n demana el valor), desenvolupat a la universitat Radboud[1] de Nimega, Holanda.
Clean és un dels llenguatges de programació funcional que més optimitza la velocitat i l'espai.[2] Clean admet l'avaluació estricta (primerenca) ocasionalment per optimitzar l'execució, mitjançant anotacions específiques d'estrictesa (avaluació primerenca) i allotjament directe. Disposa de tipus d'unicitat per modelar els efectes laterals.
Els treballs en el llenguatge Clean van començar[3] el 1984, com a part del projecte "parallel reduction machine". La primera versió es va posaar en marxa el 1987
Va tenir una gran influència en Haskell, que més tard va influenciar Clean.
Programa Hola Món [modifica]
/* fitxer prova.icl funció d'engegada Start avaluant una expressió, anomenat mode consola */ module prova import StdEnv Start:: String Start = "Hola Món!" // fi de fitxer
/* Alternativa en mode World, per operar sobre fitxers (en aquest cas stdin, stdout)
caldrà individualitzar les variables que comporten estat (ex.: world, console)
*/
Start:: *World -> *World
Start world1 = world3
where
(console1, world2)= stdio world1 // stdio obre consola per llegir i escriure[4]
console2= fwrites "Hola món!\n" console1 // escriu
(ok, world3)= fclose console2 world2 // tanca
// fi de fitxer
/* Equivalent a l'anterior amb clàusules # let-before amb avaluació no-estricta i àmbits de visibilitat de variables inclosos successivament que ens permeten obviar els estats successius d'una variable: (ex.: world1, world2, world3 de la versió anterior) */ Start:: *World -> *World Start world # (console, world)= stdio world // obre consola stdio ; àmbit més extern # console= fwrites "Hola món!\n" console // àmbit intermedi # (ok, world)= fclose console world // àmbit més intern = world // l'àmbit més intern de tots // fi de fitxer
A l'entorn Linux [modifica]
Desempaquetar el paquet de codi nadiu, llegir README, i fer make, que instal·la al directori actual
CLEAN_HOME=/camí/al/vostre/clean export PATH=$CLEAN_HOME/bin:$PATH export CLEANPATH=$CLEAN_HOME/lib/stdenv # cd al dir. de prova.icl clm prova -o prova ./prova
dóna la sortida
"Hola Món!" Execution: 0.00 Garbage collection: 0.00 Total: 0.00
A l'entorn Windows [modifica]
Clean porta un entorn de desenvolupament IDE propi per a Windows no suportat inicialment per al Linux.
No porta instal·lador. Desempaquetes a la carpeta escollida i executes el CleanIDE.exe
Característiques [modifica]
Sintaxi [modifica]
blocs delimitats pel sagnat (marge esquerra de les línies d'instruccions)
Comentaris [modifica]
// comentari fins a fi de línia
/*
comentari multi-línia
/*
comentari niuat
*/
*/
Tipus [modifica]
Tipus bàsics [modifica]
Bool[5] ops: not == && || Int[6] ops: < == Real[7] Char[8]
Atributs: Unicitat en el tipus [modifica]
Vegeu al manual el capítol Uniqueness typing.
Un tipus amb exigència d'unicitat (*Tipus) admet només referències úniques (una sola còpia) a estructures, a fi i efecte d'assegurar que no s'estigui accedint a l'estructura des d'un altre fil d'execució, i poder fer actualitzacions destructives in situ amb seguretat.
*Tipus // tipus amb atribut positiu d'unicitat (exigeix referència única)
- relació de subtipus en unicitat
- Passar una referència única a un paràmetre de funció que no requereixi unicitat és segur, però no a l'inrevés. Això estableix una relació de subtipus "únic subtipus de no-únic" que afavorirà que el compilador asseguri aquest aspecte estàticament, i que el manual representa així:
únic <= no-únic // únic subtipus (més específic) de no-únic
- restriccions d'unicitat
- En una declaració de tipus de funció, es pot acompanyar els tipus amb variables d'atribut d'unicitat, i afegir com a restricció (exemple: "[w <= x, ...]"), les relacions de subtipus que cal que compleixin els atributs d'unicitat de les variables.
v:Tipus // tipus amb variable d'atribut d'unicitat (pot avaluar a: únic / no-únic)
// per a ser especificat en les clàusules de restriccions
v <= w i w == únic implica v == únic
v <= w i v == no-únic implica w == no-únic
append :: v:[u:a] w:[u:a] -> x:[u:a] , [v<=u, w<=u, x<=u, w<=x]
// si els elem. a són únics, v, w i x també ho han de ser
// w <= x expressa que la unicitat del resultat depèn només de la del segon paràmetre.
- atribut d'unicitat anònim
- Per fer els tipus més llegibles podem obviar les variables d'atribut d'unicitat que no intervenen en les restriccions amb un punt indicant variable irrellevant, anomenada anònima
.Tipus // tipus amb variable d'atribut d'unicitat anònima
// obviable perquè no intervé en les clàusules de restriccions
- Clean permet obviar les variables i restriccions derivables de les popietats de propagació. L'anterior declaració d' append es pot escriure:
append :: [u:a] w:[u:a] -> x:[u:a] , [w<=x]
- per fer-ho més llegible:
append :: [.a] w:[.a] -> x:[.a] , [w<=x]
Altres atributs dels tipus [modifica]
#Tipus // tipus unboxed (amb allotjament directe del valor)
// altrament contindria un punter al descriptor del valor
!Tipus // tipus amb avaluació estricta (primerenca)
Tipus // sense les marques '!#': avaluació tardana (ang:lazy)
|Tipus // overloaded: admet valors amb qualsevol atribut unboxed, estrictes o tardans (ang.:lazy)
Tipus compostos [modifica]
:: ConstructorA Tipus_A Tipus_B .. // tipus producte :: ConstructorA Tipus_A Tipus_B .. | ConstructorB TipusC TipusD .. | .. // unió etiquetada (tipus suma)
:: (Tipus_A, Tipus_B) // Tupla[9] :: { numerador :: Int, denominador :: Int } // Registre
:: [Tipus] // Llista[10] :: {Tipus} // Vector (ang:Array)[11]
:: [! Tipus ] // Llista amb avaluació estricta al cap :: [ Tipus !] // Llista amb avaluació estricta de la cua :: [! Tipus !] // Llista amb avaluació estricta al cap i a la cua
lligams de tipus [modifica]
:: Complex // tipus abstracte
// sinònim o àlies de tipus // :: nom :== expressió_de_tipus
:: Complex :== (!Real, !Real)
:: String :== {#Char} // vector de caràcters unboxed (amb allotjament directe)
// definició de tipus (=) (amb variables de tipus, cas de minúscules)
:: Llista a = Nil | Cons a (Llista a) // (recursiva en aquest cas)
Enumeracions [modifica]
:: TDia = Dl | Dm | Dc | Dj | Dv | Ds | Dg
Expressions [modifica]
Macros (:==) [modifica]
Substitució de codi
Negre :== 1 Blanc :== 0
(=:) a nivell global [modifica]
Expressions constants (grafs en termes de Clean) a nivell global per a ser avaluades un sol cop.
quad :: Int quad =: expressio * 4
(=>) a tots els nivells i (=) a nivell global [modifica]
indica funció constant o en termes de Clean "regla de reescriure grafs" (ang.: rewrite rule)
Funcions [modifica]
En termes de Clean les funcions són estratègies de reducció dels grafs.
// la fletxa -> separa els paràmetres del resultat suma :: Int Int -> Int suma x y = x + y
polimòrfiques
// després de '|' hi ha els requeriments de les variables de tipus suma_i_decrement :: a a -> a | +,- a // | cal que el tipus a implementi (+) i (-) suma_i_decrement x y = x + y - 1
Funcions d'ordre superior [modifica]
aplica2cops :: (t -> t) t -> t aplica2cops f x = f (f x )
Guardes [modifica]
sign x | x < 0 = -1
| x == 0 = 0
| otherwise = 1
definicions locals [modifica]
estil declaratiu (clàusula where)
arrels a b c = [ (~b + s)/d
, (~b - s)/d
]
where
s = sqrt (b*b - 4.0*a*c)
d = 2.0*a
expressions en àmbits (clàusula let ... in)
arrels a b c = let
s = sqrt (b*b - 4.0*a*c)
d = 2.0*a
in [ (~b + s)/d
, (~b - s)/d
]
clàusules let-before [modifica]
S'executen abans de l'encaix de patrons en les definicions de funcions. No permeten definir funcions internes.
Vegeu #Programa Hola Món més amunt.
# selector = expressió // amb #, "let-before" d'execució tardana (ang:lazy) #! selector = expressió // amb #!, "let-before" estricte (exec. primerenca)
patrons [modifica]
suma_llista :: [Int] -> Int suma_llista [] = 0 suma_llista [cap : cua] = cap + suma_llista cua
alternatives [modifica]
case expressió of
patró | guarda = expressió
patró | guarda = expressió
if expressió expressió-then expressió-else
funcions anònimes [modifica]
ambdues formes valen
\ arg1 arg2 argN -> expressió \ arg1 arg2 argN = expressió
Def. d'operadors [modifica]
(!!) infixr 2 :: Bool Bool -> Bool (!!) True False = False (!!) True True = True (!!) False _ = False
Excepcions [modifica]
El manual no en parla.
Llista per comprensió [modifica]
expr1 = [(x,y) \\ x <- (0..2) , y <- (0..2) | x >= y] // torna [(0,0), (1,0), (1,1), (2,0), (2,1), (2,2)]
expr2 = [(x,y) \\ x <- (0..3) & y <- (0..2)] // torna [(0,0), (1,1), (2,2)]
Classes de tipus [modifica]
class Arith a where (+) infixl 6 :: a a -> a (-) infixl 6 :: a a -> a // versions d'operadors sobrecarregats (+) (-) en termes d'operadors específics del tipus instance Arith Int where (+) :: Int Int -> Int (+) x y = x +^ y (-) :: Int Int -> Int (-) x y = x -^ y instance Arith Real where (+) x y = x +. y (-) x y = x -. y
amb operacions derivades [modifica]
class Eq a where (==) infix 2 :: a a -> Bool // desigual (<>) infix 2 :: a a -> Bool | Eq a (<>) x y :== not (x == y) // :== (definició com a macro)
exportant tipus [modifica]
al fitxer d'interfase (.dcl) amb la clàusula definition module
definition module example
class Eq a
where
(==) infix 2 :: a a -> Bool
// special genera versions especialitzades d'operacions sobrecarregades per millorar-ne el rendiment
instance Eq [a] | Eq a // Eq [a] requereix Eq a
special a = Int // versió especialitzada per a [Int]
a = Real // versió especialitzada per a [Real]
instance Eq a
Mòduls [modifica]
d'implementació [modifica]
amb extensió ".icl"
[implementation] module nom_del_mòdul where ... import StdEnv, ... ...
d'interfície [modifica]
amb extensió ".dcl"
Cal copiar-hi les declaracions de tipus de la implementació que vulguem exportar
definition module nom_del_mòdul where especificacions exportades
Biblioteques [modifica]
Biblioteca estàndard i altres[12]
Eines [modifica]
extensions dels fitxers [modifica]
- .icl
- mòdul d'implementació
- .dcl
- mòdul d'interfície (de definició d'especificacions exportades)
- .abc
- codi intermedi (bytecode)
Vegeu també [modifica]
Referències [modifica]
- ↑ Universitat Radboud on es desenvolupa el lleng. Clean
- ↑ Debian.org - Banc de proves - Clean contra Haskell
- ↑ Preguntes freqüents sobre Clean
- ↑ StdFile - stdio obre la cònsola per llegir i escriure
- ↑ StdBool
- ↑ StdInt
- ↑ StdReal
- ↑ StdChar
- ↑ StdTuple
- ↑ StdList
- ↑ StdArray
- ↑ Biblioteca estàndard i altres al menú esquerre(anglès)
- ↑ Entorn IDE del Clean (anglès)
Enllaços externs [modifica]
- Pàgina inicial del llenguatge Clean (anglès)
- Preguntes freqüents - Wiki del llenguatge (anglès)
- El "llibre de Clean" (anglès) Guia del llenguatge
- Manual de ref. "Language report"
- Clean a Linux (anglès)
|
|||||