close

Klovn

Gå til navigation Gå til søg
klovn
Clojure logo.svg
Udvikler(e)
Richard Hickey
https://clojure.org/
Generel information
Almindelige udvidelser clj, cljs, cljc, edn og cljr
Paradigme Funktionelt , multiparadigme programmeringssprog
Dukkede op i 2007
Designet af Rich Hickey
Seneste stabile version (22-03-2022)
type system dynamisk , stærk
implementeringer JVM , CLR , JavaScript
påvirket af Lisp , ML , Haskell , Erlang Prolog
Operativ system Multi platform
Licens Eclipse Public License

Clojure er en almindelig programmeringssprogdialekt af Lisp . Det lægger særlig vægt på det funktionelle paradigme med det mål (blandt andre) at fjerne kompleksiteten forbundet med samtidig programmering . Clojure kan køres oven på Java Virtual Machine og .NET platformen virtuelle maskine , samt kompileres til JavaScript .

Principper

Rich Hickey beskriver udviklingen af ​​Clojure som at søge efter et sprog, han ikke kunne finde: en fungerende lisp som standard, bygget oven på et robust miljø i stedet for sin egen platform, og med samtidig programmering i tankerne. [ 1 ]

Ligeledes afvises objektorientering i princippet, hvilket tilbyder en tilgang, hvor programmer udtrykkes som anvendelsen af ​​funktioner på data, snarere end som interaktionen mellem foranderlige entiteter, der blander datarepræsentation og adfærd. På den anden side er funktioner som instantiabilitet, polymorfi og grænseflader effektivt en del af sproget.

Syntaks

Som resten af ​​Lisp-familien er Clojures syntaks bygget på symbolske udtryk, der konverteres til datastrukturer af en læser, inden de kompileres. Udtryk er kendetegnet ved at være afgrænset af parenteser og ved at deres præfiksnotation, hvorved det første medlem af hver liste kaldes som en funktion, videregiver resten af ​​medlemmerne som argumenter.

Denne ejendommelighed, mærkelig for dem, der er vant til de mest populære sprog baseret på C-programmeringssprogets syntaks, er grundlaget for dets fleksibilitet. Datastrukturer såsom kort , sæt og vektorer har et bogstaveligt udtryk; de kræver ingen transformation, når de inkorporeres i syntakstræet, der genereres af compileren. Clojure er en Lisp-1 og er ikke specielt designet til at være kompatibel med andre lisps .

Makro

En makro er et stykke kode, der accepterer andre udtryk som argumenter, uden at evaluere dem, transformere dem, før de evalueres. Dette giver mulighed for fremkomsten af ​​"programmer, der skaber programmer": tilføjelser til sprog-flow-kontrolstrukturerne - eller oprettelse af et domænespecifikt sprog . Muligheder i princippet ikke opnåelige i andre sprogfamilier uden at ty til udviklingen af ​​en compiler .

Clojures makrosystem minder meget om Common Lisp 's med den undtagelse, at Clojures version af backquote (kaldet et "syntaktisk citat") kvalificerer symboler med det navneområde, som de tilhører. Dette hjælper med at forhindre utilsigtet indfangning, da navnekvalificerede bindinger er forbudt. Det er muligt at tvinge udvidelsen af ​​en makro, der fanger dem, men det skal gøres eksplicit. Clojure forbyder også genbinding af globale navne i andre navneområder, der er blevet importeret til det nuværende.

Et andet træk ved det syntaktiske citat er, at det giver mulighed for et skabelonsystem , hvor du kan angive, hvilke medlemmer af en liste, der skal evalueres ved hjælp af operatorerne unquote (~) og unquote-splice (~@), hvilket fører til mere præcise makroer og overskuelig.

Sprogfunktioner

  • Dynamisk udvikling med en evalueringskonsol ( REPL: read eval print loop ).
  • Repræsentation af funktioner som værdier og en præference for rekursion og brug af højere ordens funktioner frem for iteration baseret på bivirkninger .
  • Vilkårlige præcisionstal og bogstavelig repræsentation af brøker, genereret på ikke-heltals divisioner.
  • Sekvenser med doven evaluering (elementerne i sekvensen beregnes ikke, før de er nødvendige, hvilket gør det muligt at repræsentere potentielt uendelige sæt).
  • Integreret system af vedvarende og uforanderlige datastrukturer.
  • Statskontrol (sæt af værdier, som en enhed kan erhverve over tid) i samtidige situationer gennem transaktionssystemer, agenter og gennem lokale bindinger .
  • Interaktion med java : Ved at blive kompileret til JVM bytecode kan applikationer skrevet i Clojure nemt integreres i applikationsservere eller andre Java-miljøer med lidt ekstra kompleksitet. Alle mulige grænseflader på klasse-, datastruktur- og samtidighedsniveau er implementeret som standard for at minimere den indsats, der kræves for at opnå denne portabilitet.

Eksempler

Hej verden . Bemærk, at på grund af REPL'ens natur er en printkommando ikke nødvendig .

"Hej Verden!"

En unik og fortløbende nummergenerator, der understøtter samtidige opkald:

( lad  [i  ( atom  0 ) ] 
  ( defn  generere-unik-id 
    "Returnerer en anden numerisk identifikator for hvert opkald." 
    [] 
    ( swap!  i  inc )))

En anonym underklasse af java.io.Writerdet skriver ingen steder, og en makro der bruger den til at dæmpe alle udtryk, der evalueres med den.

( def  bit-bucket-writer 
  ( proxy  [java.io.Writer]  [] 
    ( skriv  [buf]  nil ) 
    ( luk  []     nil ) 
    ( flush  []     nil )))

( defmacro  noprint 
  "Evaluerer det givne udtryk med alle udskrifter til *ud* dæmpet."   
  [&  formularer] 
  ` ( binding  [*out*  bit-bucket-writer] 
     ~@forms ))

( noprint 
 ( println  "Hej, ingen!" ))

I dette eksempel manipulerer ti tråde en delt datastruktur, som består af hundrede vektorer, der indeholder ti sekventielle start-uniktal. Hver tråd vælger to tilfældige positioner i to tilfældige vektorer og bytter dem. Alle ændringer af vektorer udføres inden for transaktioner ved hjælp af Clojures software transaktionshukommelsessystem . Det er derfor, selv efter tusinde iterationer, går intet tal tabt.

( defn  run  [nvecs  nitems  nthreads  niters] 
  ( lad  [vec-refs  ( vec  ( map  ( comp  ref  vec )) 
                           ( partition  nitems  ( range  ( *  nvecs  nitems ))))) 
        bytte  #( lad  [v1  ( rand-int  nvecs ) 
                    v2  ( rand-int  nvecs ) 
                    i1  ( rand-int  nitems ) 
                    i2  ( rand-int  nitems ) ] 
                ( dosync 
                 ( lad  [temp  ( nth  @ ( vec-refs  v1 )  i1 ) ] 
                   ( alter  ( vec-refs  v1 )  assoc  i1  ( nth  @ ( vec-refs  v2 )  i2 )) 
                   ( alter  ( vec-refs  v2 )  assoc  i2  temp )))) 
        report  #( do 
                 ( prn  ( map  deref  vec-refs )) 
                 ( println  "Distinct:" 
                          ( count  ( distinct  ( anvend  concat  ( map  deref  vec-refs )))))) ] 
    ( rapport ) 
    ( dorun  ( anvend  pcalls  ( gentag  nthreads  #( dotimes  [_  niters]  ( swap ))))) 
    ( rapport )))

( kør  100  10  10  100000 )

Output fra det foregående eksempel:

( [0  1  2  3  4  5  6  7  8  9]  [10  11  12  13  14  15  16  17  18  19]  ... 
 [990  991  992  993  994  995  996  997  998  909 :) 
1 Distinct 
 
( [382  318  466  963  619  22  21  273  45  596]  [808  639  804  471  394  904  952  75  289  778]  ... [ 
 484 216  622  152  139 2c  :  52 52 152 139 139 239 139 2    
 

Bibliografi

Eksterne links

Referencer

  1. ^ "Grundlæggende principper" . Rich Hickey (på engelsk) . Hentet 2008-10-17 dette har intet paradigme .