رفتار معکوس برخی توابع در خصوص list های quote شده

clojure

#1

من توی کدهام به یه چیز عجیب برخوردم و بعد که داکیومنت کلوژر رو نگاه کردم دیدم کلا همینطوریه.
رفتار برخی توابع چرا درمورد list برعکسه؟
مثلا اینا:


user=> (conj [\a \b \c] \d)
[\a \b \c \d]
user=> (conj '(\a \b \c) \d)
(\d \a \b \c)

user=> (pop [\a \b \c])
[\a \b]
user=> (pop '(\a \b \c))
(\b \c)

user=> (peek [\a \b \c])
\c
user=> (peek '(\a \b \c))
\a

میدونم که این کد:

'(\a \b \c)
(conj '(\a \b \c))

برابره با این:

(quote (\a \b \c))
(conj (quote (\a \b \c)))

ولی اصلا ربطی داره به این قضیه؟
پس چرا first و last متفاوت رفتار نمیکنن؟


تنها حدثی که میتونم بزنم اینه که رفتار عجیب این توابع توی ماکرو‌نویسی کمک کنه. (مثلا وقتی میخوایم یه تابعی رو به اول یه لیست اضافه کنیم)


#2

لطلفا منظور از رفتار معکوس رو بیشتر توضیح بده، چه چیزی برعکسه؟ من هیچ چیز عجیبی اینجا ندیدم


#3

خوب مثلا conj وقتی روی vector اجرا بشه، به آخر وکتور اضافه میکنه ولی وقتی روی یه list اجرا میشه به اولش اضافه میکنه!
درمورد بقیه‌ی توابع هم به همین شکل.


#4

تو Common Lisp هم همینطوره. دستور:
((cons 'a '(b c)
باعث میشه تابع cons یه لیست برگردونه که اولین عنصرش a میشه:
(a b c)
توابع cons و car (برای به دست آوردن اولین عنصر لیست) و cdr (برای به دست آوردن یه لیست شامل همۀ عنصرها به جز عنصر اول) ابتدایی ترین توابع هستن و رفتار پیشفرض اینه که عنصر مورد نظر به اول لیست اضاف بشه.
تمام توابع دیگه برای کار با لیست و آرایه رو میشه با اینا ساخت.


#5

بهتره اول اینو بگم که first و last ربطی به موضوع ندارند و کارشون نشون دادن ایتم اول و آخر هست.
و اما conj به این صورت عمل می کنه که بسته به نوع collection بهترین جا رو که کمترین منابع رو تلف کنه برای ایتم جدید در نظر میگیره, مثلا وقتی از conj برای list استفاده می کنی بر اساس اصول fp یک لیست جدید درست میشه که ایتم جدید اون در head قرار گرفته، اما در مورد vector ماجرا برعکس هست پس این موضوع به data type ربط داره.


#6

یکی از کارهای کلوژر اینه که تلاش پر ثمری برای بالابردن پرفرمنس و efficiency به صورت همزمان انجام میده، مثل collection batch processing به صورت پیشفرض و یا مثل همین مورد conj و استفاده از بهترین مکان برای ایتم های جدید هنگام ساختن یک collection جدید.


#7

در هرحال امیدوارم @lxsameer هم نظر خودشو بگه و اگر من جایی اشتباه گفتم باعث بشه که من هم اصلاح بشم :alien:


#8

خوب وقتی ما pop میکنیم دلمون میخواد از آخر یکی حذف کنه!
فکر نمیکنم هدف اینجا راندمان باشه. چون اینطوری درستی عمل فدای راندمان میشه.


#9

شما اول باید دلیل استفاده از data type مورد نظر رو روشن کنید و بعد از فانکشن های مورد نیاز استفاده کنید. کلوژر بجای اینکه بر اساس دید ما عمل کنه، بر اساس ایندکس Queue های FIFO/LIFO مربوط به هر دیتا تایپ عمل میکنه.
به هر حال من پیشنهاد می کنم از متدهای پترن مچینگ هم استفاده کنید و conj خودتون رو بنویسید


#10

همون جور که توماج عزیز فرمودند تو کلوژر interface های ثابتی برای کار های مختلف روی انواع داده مختلف وجود داره. برای مثال با conj می شه یه collection رو افزایش داد. حالا این collection هر تایپی می تونه داشته باشه لیست، وکتور، ست و غیره. هر کدوم از این تایپ ها پروتکل مربوط به conj رو بنا به پیاده سازی خودشون و پرفرمنس بهینه پیاده سازی کردند. مثلا لیست که در واقع به صورت linked list پیاده سازی شده. اگر بخوایم یه عنصر رو به آخرش اضافه کنیم باید کل لیست رو یه بار پیمایش کنیم. در صورتی که اگر به اول اضافه شه بدون نیاز به پیمایش هست. در مورد پیاده سازی وکتور این داستان بر عکس هست.

در کل همه این داستان برای این هست که شما بجای حفظ کردن یه سری تابع برای دیتا تایپ های مختلف یکی رو یاد بگیری که رفتار ثابتی داره. در عوض باید با دیتا تایپ ها آشنا باشی.