Sunday, August 16, 2015

Ծրագրերի սկզբնային տեքստերի գեղեցկության մասին

Կարելի՞ է արդյոք կոմպյուտերային ծրագրի կոդի մասին խոսելիս ասել, որ այն գեղեցիկ է։ Արդյո՞ք ծրագրի տեքստը կարելի է բնութագրել գեղագիտական հատկանիշներով։ Այս հարցին ես առաջին անգամ առնչվեցի, որբ բակալավրիատում սովորելու առաջին կուրսում, ծրագրավորման գործնական պարապմունքի ժամին դասախոսը՝ Արմեն Անդրեասյանը, ցույց տվեց գրատախտակին գրված ծրագիրը ու ասաց. «Գեղեցիկ է, չէ՞»։ Ինչքան հիշում եմ, թեև հնարավոր է, որ սխալվեմ, այդ ծրագիրը Էվկլիդեսի ալգորիթմն էր՝ գրված C++ լեզվով.

int gcd( int a, int b )
{
  while( a != b )
    if( a > b )
      a -= b;
    else
      b -= a;
  return a;
}

Այն ժամանակ մենք նույնիսկ քմծիծաղեցինք, թե ծրագրի գեղեցիկը ո՞րն է, սովորական ծրագիր է։ Հետագայում, սովորելու և աշխատելու տարիներին, երբ գրեցի շատ ու շատ ծրագրեր, երբ նաև կարդացի ուրիշների գրած շատ ու շատ ծրագրեր, համարյա միշտ ինքս ինձ հարցնում էի, թե գեղեցի՞կ է արդյոք իմ գրածն ու կարդացածը։

Էվկլիդեսի ալգորիթմին վերադառնալով ուզում եմ ասել, որ այն իսկապես գեղեցիկե։ Առավել գեղեցիկ է նրա ռեկուրսիվ իրականացումը, որ ահա գրել եմ Oberon լեզվով․

PROCEDURE Gcd( u, v : INTEGER ) : INTEGER;
VAR
  re : INTEGER;
BEGIN
  IF v = 0 THEN
    re := u
  ELSE
    re := Gcd(v, u MOD v)
  END;
RETURN re END Gcd;

Չէ, իսկապես գեղեցիկ է։ Այս ալգորիթմի համար նույնիսկ կարևոր չէ, թե այն ինչ լեզվով է գրված։ Նրա հիմքում գեղեցիկ մաթեմատիկական միտքն է, այն գեղեցիկ է ստացվելու, երևի թե ցանկացած ծրագրավորման լեզվով գրելիս։ Ճիշտ ինչպես Շիլլերի տողերը, որ միատեսակ գեղեցիկ են ինձ ծանոթ բոլոր լեզուներով։ Բնագիրը.

    Ihr Matten lebt wohl,
    Ihr sonnigen Weiden!
    Der Senn muss scheiden,
    Der Sommer ist hin.
Wir fahren zu Berg, wir kommen wieder,
Wenn der Kuckuck ruft, wenn erwachen die Lieder,
Wenn mit Blumen die Erde sich kleidet neu,
Wenn die Brünnlein fliessen im lieblichen Mai
    Ihr Matten lebt wohl,
    Ihr sonnigen Weiden!
    Der Senne muss scheiden,
    Der Sommer ist hin.

Հայերեն՝ Հ. Թումանյանի թարգմանությամբ.

Մնաք բարով, դո՛ւք, արոտնե՛ր սիրուն,
Ամառն անց կացավ, հոտն իջնում է տուն։

Մենք ետ կըգանք ձեզ նորեկ գարունքին,
Երբ զարթնեն ուրախ երգերը կըրկին,
Երբ որ սարերը զուգվեն կանաչով,
Երբ որ ջըրերը վազեն կարկաչով։

Մնաք բարով, դո՛ւք, արոտնե՛ր սիրուն,
Ամառն անց կացավ, հոտն իջնում է տուն։ 

Ռուսերեն՝ Ն. Սլավյատինսկու թարգմանությամբ.

    Прощайте, луга,
    Багряные зори!
    Разлука нам — горе.
    Ах, лето прошло!
Пора нам в долины... Увидимся снова,
Когда все очнется от сна ледяного
И голос кукушки в лесу зазвучит,
Цветы запестреют, родник зажурчит.
    Прощайте, луга,
    Багряные зори!
    Разлука нам — горе.
    Ах, лето прошло!

Անգլերեն՝ Թ. Մարտինի թարգմանությամբ.

    Farewell, ye green meadows,
    Farewell, sunny shore,
    The herdsman must leave you,
    The summer is o'er.
We go to the hills, but you'll see us again,
When the cuckoo is calling, and wood-notes are gay,
When flowerets are blooming in dingle and plain,
And the brooks sparkle up in the sunshine of May.
    Farewell, ye green meadows,
    Farewell, sunny shore,
    The herdsman must leave you,
    The summer is o'er.

Հիմա արդեն, ծրագրային կոդերի հետ աշխատանքի ավելի քան տաս տարիների փորձն ամփոփելով, կարող եմ ինքս ինձ համար պնդել, որ այո՛, կոմպյուտերային ծրագրի տեքստը (սկզբնային տեքստ, source code) նույնպես կարող է գեղեցիկ լինել։ Ավելին, հուսալի ու արդյունավետ կարող են աշխատել միայն այնպիսի ծրագրերը, որոնք գեղեցիկ տեքստ ունեն։ Համարյա ինչպես ավիացիայում. ասում են, որ լավ է թռչում միայն գեղեցիկ ինքնաթիռը։ Օրինակ, МиГ-29 կործանիչը։ Ես կարող եմ ժամերով նայել այս ինքնաթիռի թռիչքին։ Այն թռչում է ինչպես բալետի պարուհին է պարում բեմի վրա, ինչպես գեղասահորդը սահում է սառույցին։ Եվ երբ նայում եմ այդ ինքնաթիռի գծապատկերին, տեսնում եմ նույն պարուհուն կամ գեղասահորդին:

Նույնպիսի համեմատություն կարող եմ անել Դ. Կնուտի (D. Knuth) TeX և METAFONT ծրագրերի համար։ Այդ երկու ծրագրերն էլ գրված են Literate Programming մեթոդով. կարծես գեղարվեստական ստեղծագործություն լինեն։ Դե, իսկ ո՞ւմ չէ հայտնի TeX-ով պատրաստված տեքստերի և METAFONT-ով պատրաստված տպատառերի գեղեցկությունը։

Կան նաև տգեղ ծրագրեր։ Բառացիորեն վերջերս իմ աշխատանքում պետք եղավ C++ լեզվով գրել ծրագրի մի հատված, որտեղ օբյեկտները բնութագրող տողերի զույգերից պետք էր կառուցել օբյեկտների բառարան (map): Տողերի զույգի առաջին տարրը բառարանի բանալին է, իսկ երկրորդ տարրից պետք է կառուցել բանալուն համապատասխանեցված արժեքը։ Ծրագրի բնույթն այնպիսին է, որ տողերի զույգերը ժամանակի ընթացքում ավելանալու են։ Սկզբում, երբ զույգերը դեռ քիչ էին, գրել էի մի այսպիսի տեքստ (պարզեցված տարբերակով, իհարկե).

std::vector keys;
std::map dict;
keys.push_back("k0");
dict["k0"] = new Descriptor("v0");
keys.push_back("k1");
dict["k1"] = new Descriptor("v1");
keys.push_back("k2");
dict["k2"] = new Descriptor("v2");

Չնայած, որ բնութագրող տողերի փոքր քանակի համար սա ընդունելի է, այնուամենայնիվ, ես համարում եմ, որ այս կոդը տգեղ է։ Հենց թեկուզ այն պատճառով, որ տվյալները «կորել» են լեզվի արտահայտությունների մեջ։

Հետո, երբ բնութագրիչների քանակներն ավելանան, ես keys և dict կոնտեյներները լրացնելու համար կոդը ձևափոխեցի հետևյալ տեսքին.

using pair_t = std::pair;
std::list cpairs = {
    { "k0", "v0" },
    { "k1", "v1" },
    { "k2", "v2" },
    // ....
    { "k12", "v12" }
};
auto maker_f = [&]( pair_t e ) { 
                   keys.push_back(e.first);
                   dict[e.first] = new descriptor(e.second);
               };
std::vector keys;
std::map dict;
std::for_each( cpairs.begin(), cpairs.end(), maker_f );

Մի քիչ երկար է, բայց այս դեպքում, եթե նոր տվյալներ ավելացնեմ, ապա դրանք ավելացնելու եմ միայն cpairs ցուցակում, իսկ տվյալների մշակման մասն արդեն անփոփոխ է մնալու։ Պետք է նշել, որ այս գեղեցիկ տեքստը ես ստացել եմ C++11 ստանդարտում ավելացված հնարավորությունների շնորհիվ։ Եթե ես այս կոդը գրեի, C++98 ստանդարտի հնարավորություններով, ապա ստանալու էի մի կոդ, որին ես գեղեցիկ ասել չեմ կարող.

typedef std::pair pair_t;
std::list cpairs;
cpairs.push_back( std::make_pair( "k0", "v0" ) );
cpairs.push_back( std::make_pair( "k1", "v1" ) );
cpairs.push_back( std::make_pair( "k2", "v2" ) );
// ....
cpairs.push_back( std::make_pair( "k12", "v12" ) );

std::vector names;
std::map dict;
for( std::list::iterator it = cpairs.begin(); it != cpairs.end(); ++it ) {
    names.push_back( it->first );
    dict[it->first] = new Descriptor(it->second);
}

Ցանկացած ծրագրում կարելի է գտնել այսպիսի օրինակներ։ Ցանկացած այսպիսի օրինակի գեղեցկության կամ տգեղության մասին կարելի է վիճել։ Բայց ինձ համար մի բան հաստատ է. ծրագրավորումը կարելի է համարել կիրառական արվեստի մի ճյուղ։ Եվ տեղին է այդ արվեստի նմուշների համար օգտագործել գեղեցիկ և տգեղ բնութագրումները։ Իսկ ծրագրավորողներին ու թեսթավորողներին, այն մարդկանց, ովքեր իրենք առօրյա աշխատանքում գրում ու կարդում են հարյուրավոր ու հազարավոր տողերով ծրագրային տեքստ, մնում է այդ գործում գտնել ու գնահատել գեղեցիկը։

No comments:

Post a Comment