مسیرها
/
jq
jq
/
تمرین‌ها
/
توابع بازگشتی
توابع بازگشتی

توابع بازگشتی

تمرین یادگیری

مقدمه

بازگشت

«توابع بازگشتی» توابعی هستند که خودشان را فراخوانی می‌کنند.

یک تابع بازگشتی باید دست‌کم یک «حالت پایه» و دست‌کم یک «حالت بازگشتی» داشته باشد.

یک حالت پایه مقداری را برمی‌گرداند بدون اینکه تابع را دوباره فراخوانی کند. یک حالت بازگشتی تابع را دوباره فراخوانی می‌کند و ورودی را طوری تغییر می‌دهد که در نقطه‌ای با حالت پایه مطابقت پیدا کند.

در اینجا مثالی را می‌بینید که عنصرهای یک آرایه را می‌شمارد.

def count:
  if length == 0 then
    0                       # base case
  else
    1 + (.[1:] | count)     # recursive case
  end;

([] | count),           # => 0
([11, 22, 33] | count)  # => 3

یک تابع بازگشتی می‌تواند چندین حالت پایه و/یا چندین حالت بازگشتی داشته باشد. برای نمونه، دنباله‌ی فیبوناچی یک دنباله‌ی بازگشتی با دو حالت پایه است.

def fibonacci:
  if . == 0 then
    0
  elif . == 1 then
    1
  else
    (. - 1 | fibonacci) + (. - 2 | fibonacci)
  end;

10 | fibonacci          # => 55

شمردن تعداد تکرارهای یک مقدار مشخص مثل x در یک فهرست، دو حالت بازگشتی دارد.

def count_occurrences(x):
  if length == 0 then
    0
  elif first == x then
    1 + (.[1:] | count_occurrences(x))
  else
    (.[1:] | count_occurrences(x))
  end;

[11, 22, 33, 22, 44] | count_occurrences(22)    # => 2

در عمل، پیمایش فهرست‌ها و دیگر ساختارهای داده‌ای قابل شمارش بیشتر وقت‌ها با توابع داخلی انجام می‌شود، مثل map و reduce، یا با استفاده از جریان‌ها مانند [.[] | select(...)]. در لایه‌های زیرین، بعضی از توابع داخلی با بازگشت پیاده‌سازی شده‌اند.

دستورالعمل‌ها

شما تازه به تیمی پیوسته‌اید که یک خط لوله‌ی داده‌ی مبتنی بر jq را نگهداری می‌کند. در اولین جلسه‌ی برنامه‌نویسی دونفره‌تان، همکار جدیدتان کنجکاو می‌شود: «آیا می‌دانید add، reverse و map در پشت صحنه چگونه کار می‌کنند؟ بیایید بررسی کنیم؛ امتحان کنید و خودتان آن‌ها را با استفاده از بازگشت پیاده‌سازی کنید، بدون استفاده از توابع درون‌ساخت.»

1. یک تابع برای جمع زدن اعداد یک آرایه پیاده‌سازی کنید

فیلتر درون‌ساخت add را دوباره پیاده‌سازی می‌کنیم تا بازگشت را تمرین کنیم. حالت پایه این است که مجموع یک آرایه‌ی خالی صفر است.

خودتان آن را با یک تابع بازگشتی پیاده‌سازی کنید؛ از add درون‌ساخت استفاده نکنید.

[5, 4, 6, 10] | array_add     # => 25

2. یک آرایه را برعکس کنید

فیلتر درون‌ساخت reverse را دوباره پیاده‌سازی می‌کنیم. حالت پایه این است که برعکس کردن یک آرایه‌ی خالی، یک آرایه‌ی خالی است.

خودتان آن را با یک تابع بازگشتی پیاده‌سازی کنید؛ از reverse درون‌ساخت استفاده نکنید.

[5, 4, 6, 10] | array_reverse   # => [10, 6, 4, 5]

3. اعمال map روی یک آرایه

فیلتر درون‌ساخت map را دوباره پیاده‌سازی می‌کنیم. این تابع یک فیلتر را به‌عنوان پارامتر می‌گیرد، آن فیلتر را برای هر عنصر از آرایه‌ی ورودی اجرا می‌کند و خروجی‌ها را در یک آرایه‌ی جدید برمی‌گرداند. حالت پایه این است که آرایه‌ی خالی به آرایه‌ی خالی نگاشت می‌شود.

خودتان آن را با یک تابع بازگشتی پیاده‌سازی کنید؛ از map درون‌ساخت استفاده نکنید.

[5, 4, 6, 10] | array_map(. + 10)   # => [15, 14, 16, 20]
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
jq Exercism

آماده‌اید توابع بازگشتی را شروع کنید؟

در Exercism ثبت‌نام کنید تا jq را همراه با 12 مفهوم75 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.