ყველა სტატია

სტატია

როგორ ასახავს ქართული ხალხური ზღაპარი ფუნქციების გამოძახების სტეკს

ქართული კულტურა და კომპიუტერული მეცნიერება ერთ ამბავში იკვეთება: „რწყილი და ჭიანჭველა“ გვიჩვენებს, როგორ იზრდება და შემდეგ საპირისპირო მიმართულებით იცლება გამოძახების სტეკი.

რამდენიმე დღის წინ ბათუმში გამართულ კონფერენციაზე ფურიო ჰონსელს გავესაუბრე. ფურიო ერთ-ერთი ყველაზე საინტერესო ადამიანია, ვისაც კი ოდესმე შევხვედრივარ. გამიმართლა, რომ ჩემს საბაკალავრო ნაშრომსაც ის ხელმძღვანელობდა.

მას ქართული კულტურა აინტერესებს და ხშირად მეკითხება მის შესახებ. რადგან მათემატიკოსია, საუბარი ხშირად მათემატიკურ ჭრილში გადადის. მეც სიამოვნებით ვეძებ ქართულ კულტურასა და ენაში პატარა, მოულოდნელ დეტალებს, რომლებიც შემიძლია მას გავუზიარო.

იმ საღამოს ვფიქრობდი, კიდევ რა საინტერესო მაგალითი გამეზიარებინა მისთვის, როცა ჩემმა შეყვარებულმა ქართული ხალხური ზღაპარი „რწყილი და ჭიანჭველა“ გამახსენა. ამბავი მოკლეა, ამიტომ აქვე შევაჯამებ.

თუ პროგრამისტი ხართ, ალბათ უკვე მიხვდით, საით მიმყავს ეს ამბავი.

თხოვნათა ეს ჯაჭვი ძალიან ჰგავს პროგრამაში ფუნქციების გამოძახების სტეკს (Call Stack). თითოეულ პერსონაჟს რაღაც აქვს გასაკეთებელი, მაგრამ საქმეს ჯერ ვერ ასრულებს, ამიტომ დახმარებას სხვას სთხოვს და პასუხს ელოდება.

ფუნქციის გამოძახების დროსაც იგივე ხდება. როცა ერთი ფუნქცია მეორეს იძახებს, პირველი დროებით ჩერდება, სტეკს კი ახალი ჩარჩო (Stack Frame) ემატება. ასე გრძელდება, სანამ ბოლოს გამოძახებული ფუნქცია შედეგს არ დააბრუნებს. შემდეგ სტეკი თანდათან, საპირისპირო რიგით იცლება: ყოველი ფუნქცია თავის საქმეს ასრულებს და მართვას გამომძახებელ ფუნქციას უბრუნებს.

რატომ აქვს თანმიმდევრობას მნიშვნელობა

რწყილი ღორს დახმარებას ამბის დასაწყისშივე სთხოვს, თუმცა ღორი ვერ დაეხმარება, სანამ ჯაჭვის ყველა დანარჩენი მონაწილე თავის საქმეს არ შეასრულებს. ძროხა თხოვნას ბოლოს იღებს, მაგრამ პასუხს პირველი სწორედ ის გასცემს. ამის შემდეგ შედეგი ჯაჭვს საპირისპირო მიმართულებით მიუყვება.

სწორედ ეს საპირისპირო მიმდევრობაა მთავარი. სტეკი პრინციპით „ბოლოს შესული, პირველი გამოსული“ (LIFO) მუშაობს: ბოლოს გამოძახებული ფუნქცია პირველი სრულდება. მისი ჩარჩო სტეკიდან ამოიღება, მის ქვემოთ მოთავსებული ფუნქცია კი მუშაობას იქიდან აგრძელებს, სადაც შეჩერდა.

მაგალითად, getMilk() მუშაობას აჩერებს, როცა getGrass()-ს იძახებს. getGrass() ბალახს აბრუნებს და მისი ჩარჩო სტეკიდან მოშორდება. ამის შემდეგ getMilk() მუშაობას აგრძელებს, რძეს მოიპოვებს და moveMouse()-ს უბრუნებს. გაცილებით მოგვიანებით getBristle() ჯაგარს makeRope()-ს გადასცემს, ის კი მისგან თოკს დაგრეხს და rescueAnt()-ს დაუბრუნებს.

რითი ჰგავს ზღაპარი პროგრამას

ეს ზღაპარი, რა თქმა უნდა, კომპიუტერული პროგრამა არ არის და ნაკლებად სავარაუდოა, რომ მისი შექმნისას ვინმეს გამოძახების სტეკზე ეფიქრა. მათ სტრუქტურაში მსგავსება მაინც აშკარაა: თხოვნები ერთი მიმართულებით გროვდება, პასუხები კი საპირისპირო მიმართულებით ბრუნდება.

ფუნქციის თითოეულ ჩარჩოში ინახება ინფორმაცია, რომელიც მას მუშაობის გასაგრძელებლად დასჭირდება, მათ შორის, ლოკალური ცვლადები და დაბრუნების მისამართი. ზღაპრის პერსონაჟებიც გარკვეულწილად მსგავსად იქცევიან: სანამ მომდევნო თხოვნის შესრულებას ელოდებიან, თითოეულ მათგანს ახსოვს, რას დაჰპირდა რწყილს.

დასასრულს

ზღაპრის მთავარი სათქმელი მეგობრობა, შეუპოვრობა და გასაჭირში მყოფის დახმარებაა. გამოძახების სტეკთან მსგავსება კი მხოლოდ მოულოდნელი პარალელია. სწორედ ამ პარალელის დანახვამ გამაცოცხლებინა ნაცნობი ამბავი ახლებურად.

ახლა ფურიოს მომდევნო კითხვაზეც კარგი პასუხი მაქვს: შემიძლია ვუთხრა, რომ ერთ ქართულ ხალხურ ზღაპარში ფუნქციების გამოძახების სტეკის საოცრად ზუსტი მოდელი იმალება.