Clean

De Viquipèdia
Dreceres ràpides: navegació, cerca

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 | modifica el codi]

Avaluació d'expressions a partir de la funció principal Start

  • anomenat mode consola
 /* 
    fitxer prova.icl
 */
 module prova
 
 import StdEnv 
 
 Start:: String
 Start = "Hola Món!"
  • Operació sobre fitxers (en aquest cas stdin, stdout)
  • anomenat mode World
  • amb clàusules where, caldrà individualitzar les variables que designen els diferents estats de l'entorn.
 /* Alternativa en ''mode World'', 
    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<ref>[http://clean.cs.ru.nl/Download/Download_Libraries/Std_Env/StdFile/stdfile.html StdFile - stdio obre la cònsola per llegir i escriure]</ref>
     console2 = fwrites "Hola món!\n" console1  // escriu
     (ok, world3) = fclose console2 world2      // tanca
  • mode World amb clàusules let-before d'avaluació tardana designades per '#'
  • les clàusules let-before s'executen abans de l'encaix de patrons
  • aquí són d'exec. tardana i constitueixen una sequència similar als blocs monàdics del Haskell
  • no caldrà individualitzar les variables que comporten estat (console, world) perquè els àmbits de visibilitat tapen els estats anteriors de les variables.
 /* Equivalent a l`anterior amb clàusules # ''let-before''
    i àmbits de visibilitat de variables inclosos successivament
    * els àmbits de visibilitat taparan les variables anteriors 
         del mateix nom corresponents a estats anteriors
 */
 
 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                                       // crida al darrer ''world'',

A l'entorn Linux[modifica | modifica el codi]

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 | modifica el codi]

Clean porta un entorn de desenvolupament IDE propi per a Windows no suportat inicialment per al Linux.

No porta insta·llador. Desempaquetes a la carpeta escollida i executes el CleanIDE.exe

Característiques[modifica | modifica el codi]

Sintaxi[modifica | modifica el codi]

blocs delimitats pel sagnat (marge esquerra de les línies d'instruccions)

Comentaris[modifica | modifica el codi]

// comentari fins a fi de línia

/* 
  comentari multi-línia
   /* 
      comentari niuat
   */
*/

Tipus[modifica | modifica el codi]

Tipus bàsics[modifica | modifica el codi]

Bool[4]
  ops: not == && ||

Int[5]
  ops: < ==                

Real[6]

Char[7]

Atributs: Unicitat en el tipus[modifica | modifica el codi]

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 | modifica el codi]

segons prefix amb els símbols '#', '!', sense i '|'

#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 | modifica el codi]

:: ConstructorA Tipus_A Tipus_B ..         // tipus producte

:: ConstructorA Tipus_A Tipus_B .. | ConstructorB TipusC TipusD .. | ..     // unió etiquetada (tipus suma)
:: (Tipus_A, Tipus_B)   // Tupla[8]

:: { numerador :: Int, denominador :: Int }     // Registre
:: [Tipus]              // Llista[9]

:: {Tipus}              // Vector (ang:Array)[10]
:: [! 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 | modifica el codi]

:: 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 | modifica el codi]

:: TDia = Dl | Dm | Dc | Dj | Dv | Ds | Dg

Expressions[modifica | modifica el codi]

Macros (:==)[modifica | modifica el codi]

Substitució de codi

Negre :== 1
Blanc :== 0

(=:) a nivell global[modifica | modifica el codi]

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 | modifica el codi]

indica funció constant o en termes de Clean "regla de reescriure grafs" (ang.: rewrite rule)

Funcions[modifica | modifica el codi]

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 | modifica el codi]

aplica2cops :: (t -> t) t -> t
aplica2cops f x = f (f x )

Guardes[modifica | modifica el codi]

sign x | x < 0  = -1
       | x == 0 = 0
       | otherwise = 1

definicions locals[modifica | modifica el codi]

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 | modifica el codi]

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 | modifica el codi]

suma_llista :: [Int] -> Int
suma_llista [] = 0
suma_llista [cap : cua] = cap + suma_llista cua

alternatives[modifica | modifica el codi]

case expressió of
      patró | guarda = expressió
      patró | guarda = expressió
if expressió expressió-then expressió-else

funcions anònimes[modifica | modifica el codi]

ambdues formes valen

\ arg1 arg2 argN -> expressió

\ arg1 arg2 argN = expressió

Def. d'operadors[modifica | modifica el codi]

(!!) infixr 2 :: Bool Bool -> Bool
(!!) True False = False
(!!) True True = True
(!!) False _ = False

Excepcions[modifica | modifica el codi]

El manual no en parla.

Llista per comprensió[modifica | modifica el codi]

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 | modifica el codi]

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 | modifica el codi]

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 | modifica el codi]

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 | modifica el codi]

d'implementació[modifica | modifica el codi]

amb extensió ".icl"

[implementation] module nom_del_mòdul where
...
import StdEnv, ...
...

d'interfície[modifica | modifica el codi]

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 | modifica el codi]

Biblioteca estàndard i altres[11]

Eines[modifica | modifica el codi]

  • Entorn de desenvolupament IDE [12]

extensions dels fitxers[modifica | modifica el codi]

.icl
mòdul d'implementació
.dcl
mòdul d'interfície (de definició d'especificacions exportades)
.abc
codi intermedi (bytecode)

Vegeu també[modifica | modifica el codi]

Referències[modifica | modifica el codi]

  1. Universitat Radboud on es desenvolupa el lleng. Clean
  2. Debian.org - Banc de proves - Clean contra Haskell
  3. Preguntes freqüents sobre Clean
  4. StdBool
  5. StdInt
  6. StdReal
  7. StdChar
  8. StdTuple
  9. StdList
  10. StdArray
  11. Biblioteca estàndard i altres al menú esquerre(anglès)
  12. Entorn IDE del Clean (anglès)

Enllaços externs[modifica | modifica el codi]