Լիսպ

Լիսպը (LISP, անգլ. LISt Processing – «ցուցակների մշակման լեզու») ծրագրավորման լեզուների ընտանիք է, որում տվյալներն ու ծրագրերը ներկայացվում է գծային ցուցակների միջոցով։
Լիսպի հիմնադիր Ջոն ՄակՔարտին զբաղվում էր արհեստական ինտելեկտի հետազոտություններով և նրա կողմից ստեղծված լեզուն հանդիսանում է արհեստական ինտելեկտի մոդելավորման հիմնական միջոցներից մեկը։

Ավանդական լիսպում օգտագործվում է տիպերի դինամիկ համակարգը։ Լեզուն համարվում է ֆունկցիոնալ, սակայն ունի սիմվոլների մշակման լիարժեք համակարգ, որը թույլ է տալիս իրականացնել օբեկտ-կողմնորոշվածություն, որի օրինակ է CLOS պլատֆորման։

Ճարտարապետություն և շարահյուսություն

Լեզվի հիմնական տարրերը

Լեզվի հիմնական տարրեր են հանդիսանում սիմվոլները, ատոմները և դրանցից կառուցված ցուցակները՝ S-արտահայտությունները։

Լիսպում սիմվոլը օբեկտ է մեքենայական հիշողության մեջ, որը հանդիսանում է սլոթերի ամբողջականություն և պահում է հղումներ։ Սլոթերի մի մասն ունի լեզվի կողմից նախապես որոշված նշանակություն.
 անուն – նիշերի տող, ըստ որի ծրագիրը կարող է հղվել տվյալ սիմվոլի վրա։
 Ֆունկցիոնալ սլոթ – սիմվոլի հետ կապակցված լամբդա արտահայտություն։ Երբ ծրագրում սիմվոլին դիմելու հնարավորությունը շարահյուսորեն համապատասխանում է ֆունկցիայի կանչի, հաշվարկվում է սիմվոլի հետ կապված լամբդա արտահայտություն։
 արժեք – օբեկտ մեքենայական հիշողության մեջ, որը կարելի է մեկնաբանել ինչպես տվյալները։ Երբ ծրագիրը սիմվոլին դիմում է որպես փոփոխականի, ստանում է տվյալ սլոթի արժեքը։

Սլոթերի հավաքածուն դինամիկ ընդլայնվող է և կարող է օգտագործվել որպես սիմվոլի անկախ հատկությունների ցուցակ։	

Ատոմները սիմվոլներն են և թվերը։ Թվերը չեն հանդիսանում լիսպի սիմվոլներ, քանի որ կարող են ընդունել միայն սեփական թվային արժեքը։ Բայց միաժամանակ թվերը կարող են սլոթերին հավասար ընդգրկվել ցուցակների մեջ։ Դրանով ել պայմանավորված է դրանց միավորումը միասնական կատեգորիայի մեջ։

Լիսպում տվյալների հիմնական կառուցվածքը ատոմների դինամիկ ցուցակն է, որը ռեկուրսիվ սահմանվում է որպես “գլուխ”-օբեկտ և նրան ամրացված ցուցակ-“պոչ”: Քանի որ գլուխն իր հերթին կարող է լինել ցուցակ, ցուցակը փաստացի հանդիսանում է ծառի մոդել ( վերին մակարդակի ցուցակ – արմատ, դրա մեջ մտնող ենթացուցակներ – ճյուղեր, ատոմներ – տերևներ )։ Ատոմների և ցուցակների համար լեզուն օգտագործում է պարզ, փակագծերով շարահյուսություն. սիմվոլը ներկայացվում է անունով, թիվը՝ իր արժեքով, իսկ ցուցակը՝ կլոր փակագծերում գրված ատոմների և ցուցակների հաջորդականությամբ։

Ցուցակում կարող են ընդգրկված լինել ցանկացած տիպի էլեմենտներ՝ այդ թվում նաև ցուցակներ։ Օրինակ.

(1 3/7 'foo #'+)

ցուցակը բաղկացած է ամբողջ թվից, կոտորակից, foo սիմվոլից և գումարման ֆունկցիայի վրա ցուցչից։

Արտահայտություններն իրենցից ներկայացնում են պրեֆիքս գրառմամբ ցուցակներ. Առաջին էլեմենտը պետք է լինի ֆունկցիա, օպերատոր կամ մակրոս։

Թվաբանական արտահայտությունները նույնպես գրառվում են այդ սկզբունքով, օրինակ

 (+ 4 (* 2 3))

արտահայտությունը վերադարձնում է 10 ( ինֆիքս գրառումն է 2 * 3 + 4 )։
 s_expression ::= atomic_symbol | "(" s_expression "." s_expression ")" | list 
 list ::= "(" s_expression { s_expression } ")" 
 atomic_symbol ::= letter atom_part 
 atom_part ::= empty | letter atom_part | number atom_part 
 letter ::= "a" | "b" | " ..." | "z" 
 number ::= "1" | "2" | " ..." | "9" 
 empty ::= " "

Լիսպով գրված ծրագրի առանձնահատկությունն այն է, որ տվյալները և ցանկացած բարդության կոդ բնութագրվում է վերը նշված պարզ քերականությամբ։

Բազային սիմվոլներ, օպերատորներ և ֆունկցիաներ

Լիսպի վերջին իրագործումներն ունեն բազմաթիվ ֆունկցիաներ, մակրոսներ և օպերատորներ։ Այստեղ ներկայացված են նրանք, որոնք կազմում են ցուցակների հետ աշխատելու և լիսպով ֆունկցիոնալ ծրագրեր ստեղծելու հիմնական բազիսը։

T  և NIL

Լիսպի ներկառուցված սիմվոլ – հաստատուններ, որոնք ցույց են տալիս տրամաբանական արտահայտության ճշմարիտ կամ կեղծ լինելը համապատասխանաբար։

NIL սիմվոլն ունի ևս մեկ կիրառում – այն նաև կարող է նշանակել դատարկ ցուցակ։

LIST

Հետևյալ ֆունկցիան վերադարձնում է իր արգումենտների ցուցակը.

(list 1 3/7 'foo) ==>> (1 3/7 'foo)  

(այստեղ, նաև հաջորդ օրինակներում «==>>» նշանակումը ցույց է տալիս որ ձախ մասի հաշվարկի արդյունքում վերադարձվում է աջ մասում գրվածը)։ Եթե արգումենտ չկա, վերադարձվում է դատարկ ցուցակ.

 (list) ; ==>> NIL

Եթե որևէ արգումենտ իրենից ներկայացնում է արտահայտություն, ապա սկզբում հաշվարկվում է դրա արժեքը.

(list 1 2 (list 1 2))  ; ==>> (1 2 (1 2))

QUOTE

Լիսպի ինտերպրետատորը, մուտքում ստանալով ցուցակ կամ սիմվոլ, փորձում է այն հաշվել։ Եթե անհրաժեշտ է, որ ինտերպրետատորը չհաշվարկի արժեք, այլ վերցնի սիմվոլը կամ ցուցակն այնպես, ինչպես կա, պետք է կիրառել QUOTE.

(list 1 2 (quote (list 1 2)))  ; ==>> (1 2 (LIST 1 2))
(quote (list 1 2 (list 1 2))) ; ==>> (LIST 1 2 (LIST 1 2))

QUOTE–ի լրիվ կանչի ձևի փոխարեն կարելի է արտահայտությունից առաջ ուղղակի ապաթարց դնել.

(list 1 2 '(list 1 2))  ; ==>> (1 2 (LIST 1 2))

EVAL

Այս ֆունկցիան հենց լիսպի ինտերպրետատորն է։ Այն QUOTE֊ի հակադիրն է և հաշվում է իր արգումենտի արժեքը։ Օրինակ.

(eval '(list 1 2 '(list 1 2)))         ; ==>> (1 2 (LIST 1 2))
(eval '(list 1 2 (eval '(list 1 2))))  ; ==>> (1 2 (1 2))

CAR
Վերադարձնում է ցուցակի գլուխը՝ առաջին տարրը.

(car '(A B C D))     ; ==>> A
(car '((A B)(C D)))  ; ==>> (A B)

Բացառություն.
 (car NIL) ==>> NIL

Ֆունկցիոնալ ծրագրավորման մեջ դատարկ ցուցակի գագաթի արժեքն անորոշություն է, բայց լիսպում ընդունված է, որ դատարկ ցուցակի և՛ գլուխը, և՛ պոչը հավասար են NIL։

CDR

Վերադարձնում է ցուցակի պոչը։ Օրինակ.
 (CDR '(A B C D)) ==>> (B C D)
 (CDR '((A B)(C D))) ==>> ((C D))
 (CDR NIL) ==>> NIL

C?R
Այստեղ ?-ի փոխարեն կարող է լինել 2 – ից 4 “A” և “D” տառ՝ ցանկացած կոմբինացիայով։ Այսինքն հնարավոր են CDDDDR, CADAR, CADDR և այլն։ Այդպիսի ֆունկցիայի կանչին համապատասխանում է CAR և CDR ֆունկցիաների ներդրված կանչին, օրինակ (CADAR '((A B C) D E F)) –ին համապատասխանում է 
(car (cdr (car '((A B C) D E F))))  ; ==>> վերադարձնում է B–ի արժեքը։

CONS
Որպես արգումենտ ընդունում է գլուխ և պոչ և դրանցից կառուցում է ցուցակ կամ կետային զույգ, եթե արգումենտներն ատոմներ են։
(cons 'A '(B C D))      ; ==>> (A B C D) - միացնում է ատոմը ցուցակին
(cons '(A B) '((C D)))  ; ==>> ((A B) (C D)) - միացնում է մի ցուցակը մյուսի գագաթից
(cons 'A 'B)            ; ==>> (A . B) - ստեղծում է կետային զույգ 2 ատոմներից

COND
Պայմանի ընդհանրացված կառուցվածք։ Ունի հետևյալ տեսքը.

(cond ((պայման1) (արտահայտություն1)) ((պայման2) (արտահայտություն2)) … ) 

Հաջորդաբար հաշվարկվում են պայման1, պայման2, և այլն, այնքան, մինչև N – րդ պայմանը ճշմարիտ լինի։ Ապա հաշվարկվում է արտահայտությունN–ը և դրա արժեքը վերադարձվում է որպես cond-ի կանչի արդյունք։ Եթե ճշմարիտ պայման չկա վերադարձվում է NIL։ Սովորաբար որպես երջին պայման կիրառում են T–ն, որն ապահովում է, որ եթե ոչ մի պայման ճշմարիտ չէ, ապա կկատարվի վերջին արտահայտությունը։ Դա համապատասխանում է իմպերատիվ ծրագրավորման լեզուներում ELSE – օպերատորին։

DEFUN
Կառուցվածք է, որը թույլ է տալիս սահմանել ֆունկցիա և ունի հետևյալ ընդհանրացված տեսքը.

(defun անուն (պարամետր1  պարամետր2 …) արտահայտություն  արտահայտություն  …)

 Անուն – ֆունկցիայի անուն։
 Պարամետր1, և այլն, հաջորդականությունը – ֆունկցիայի ֆորմալ պարամետրեր։

Արտահայտություն1, և այլն, հաջորդականությունը – հաշվարկվող արտահայտություններ, որոնցում կարող են օգտագործվել ֆորմալ պարամետրերը և գլոբալ փոփոխականները։ Ֆունկցիայի կանչի ժամանակ արտահայտությունները հաշվարկվում են հաջորդաբար և որպես ֆունկցիայի վերադարձվող արժեք ծառայում է վերջին արտահայտության հաշվարկից ստացված արդյունքը։

Հղումներ

Ծրագրավորում
Ամերիկյան հայտնագործություններ