Clojure/თანმიმდევრობები

თანმიმდევრობები (sequences) არსებითად არიას იდიომური Clojure პროგრამირების ბირთვი. თანმიმდევრობების და მათზე მომუშავე ფორმების გაგებით, თქვენ გადალახავთ ყველაზე რთულ ნაწილს, რომელიც საჭიროა სერიოზული Clojure პროგრამის წერაში.

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

Clojure-ს ოფიციალურ ვებ გვერდზე არის თანმიმდერობის შესანიშნავი განმარტება.

მოდით, მივიღოთ თანმიმდევრობა ვექტორიდან:

user=> (seq [1 2 3])
(1 2 3)

ამ კოდს ვექტორი უბრალოდ სიაში კი არ გადაჰყავს. ის ქმნის ვექტორის თანმიმდევრობას. REPL (Read, Evaluate, Print, Loop), როდესაც ცდილობს ეკრანზე გამოიყვანას, თანმიმდევრობას სიის სახით გვიჩვენებს.

ერთ-ერთი საშუალება REPL-ს აუკრძალოთ თანმიმდევრობის სიის სახით წარმოადგინოს, არის მოვაქციოთ ის სხვა გამოსახულებაში, რომელიც არ ცვლის თანმიმდევრობას. მაგალითად, გამოვიძახოთ მეთოდი ამ თანმიმდევრობაზე. ავიღოთ, მაგალითისთვის, getClass() მეთოდი:

user=> (.getClass (seq [1 2 3]))
clojure.lang.APersistentVector$Seq

ის რაც დაბრუნდა არის APersistentVector$Seq, რაც არის ვექტორის მიმდევრობის კლასი.

Clojure-ს ყველა ჩადგმულ სტრუქტურად აქვს მეთოდი თანმიმდევრობის მისაღებად. თანმიმდევრობის ინტერფეისი ფორმალურად არის clojure.lang.iSeq, ან უბრალოდ iSeq.

გამოიყენეთ first, რომ მიიღოთ თანმიმდევრობის პირველი ელემენტი:

user=> (first (seq [1 2 3]))
1

first-ს აგრეთვე შეუძლია არგუმენტად მიიღოს უშუალოდ ვექტორი, და არაცხადად გარდაქმნას ის თანმიმდევრობად:

user=> (first [1 2 3])
1

user=> (first ["a" "b" "c"])
"a" 

user=> (first '("A" "B" "C"))
"A" 

user=> (first '(:a :b :c))
:a

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

rest გვაძლევს თანმიმდევრობას, რომელიც შეიცაცს საწყისი თანმიმდევრობის ყველა წევრს, გარდა პირველისა.

user=> (rest [1 2 3])
(2 3)

user=> (rest ["a" "b" "c"])
("b" "c")

user=> (rest '("A" "B" "C"))
("B" "C")

user=> (rest [:a :b :c])
(:b :c)

გაითვალისწინეთ, რომ არანაირი ახალი მონაცემთა სტრუქტურა არ იქმნება. rest მხოლოდ ქმნის ლოგიკურ სიას (თანმიმდევრობას). მომხმარებელზეა დამოკიდებული შექმნის თუ არა ის აქედან მონაცემთა სტრუქტურას. ზედა მაგალითებში, გამომძახებელია REPL, რომელიც ცდილობს თანმიმდევრობის სიაში გადაყვანას, რომ გამოიტანოს რამე გასაგები ეკრანზე. გამოთვლის დროს, კომპიუტერის რესურსების ხარჯვის მხრივ, თანმიმდევრობის შექმნა მეტად ეკონომიურია.

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

user=> (cons 1 [2 3])
(1 2 3)

user=> (cons :a [:b :c])
(:a :b :c)

აქაც იგივეა, არანაირი ახალი მონაცემთა სტრუქტურა არ იქმნება cons-ის მიერ. შედგებილი თანმიმდევრობა შინაგანად შედგება მხოლოდ პირველი და მეორე არგუმენტებზე რეფერენსებისგან (pointer). თუმცა მომხმარებლისთვის ისე ჩანს თითქოს ეს ერთიანი თანმიმდევრობაა.