توابع بازگشتی توابعی هستند که خودشان را فراخوانی میکنند.
یک تابع بازگشتی باید دستکم یک «حالت پایه» و دستکم یک «حالت بازگشتی» داشته باشد.
حالت پایه مقداری را برمیگرداند، بدون اینکه تابع را دوباره فراخوانی کند. حالت بازگشتی تابع را دوباره فراخوانی میکند و ورودی را طوری تغییر میدهد که در نقطهای با حالت پایه مطابقت کند.
بسیار پیش میآید که هر حالت در بند تابع جداگانهی خودش نوشته میشود.
# base case
def count([]), do: 0
# recursive case
def count([_head | tail]), do: 1 + count(tail)
یک تابع بازگشتی میتواند حالتهای پایهی زیادی و/یا حالتهای بازگشتی زیادی داشته باشد. برای نمونه دنبالهی فیبوناچی یک دنبالهی بازگشتی با دو حالت پایه است:
def fibonacci(0), do: 0
def fibonacci(1), do: 1
def fibonacci(n), do: fibonacci(n - 1) + fibonacci(n - 2)
شمارش تعداد تکرارهای یک مقدار مشخص مانند x در یک فهرست، دو حالت بازگشتی دارد:
def count_occurrences([], _x), do: 0
def count_occurrences([x | tail], x), do: 1 + count_occurrences(tail, x)
def count_occurrences([_ | tail], x), do: count_occurrences(tail, x)
به دلیل تغییرناپذیری، حلقهها در Elixir متفاوت از زبانهای امری نوشته میشوند. برای نمونه، حلقهها معمولاً چنین شکلی دارند:
for(i = 0; i < array.size; i++) {
# do something with array[i]
}
در یک زبان تابعی، تغییر دادن i (با اجرای i++) ممکن نیست. بنابراین، حلقهها باید با بازگشت پیادهسازی شوند.
معادل یک حلقهی for در Elixir چنین شکلی خواهد داشت:
def loop([]), do: nil
def loop([head | tail]) do
do_something(head)
loop(tail)
end
در عمل، پیمایش فهرستها و دیگر ساختارهای دادهی قابل شمارش بیشتر وقتها با استفاده از ماژول Enum انجام میشود. در پشت صحنه، توابع ماژول Enum با استفاده از بازگشت پیادهسازی شدهاند.
توابع بازگشتی، اگر نادرست پیادهسازی شوند، ممکن است هرگز نتیجهشان را برنگردانند. این میتواند دردسرساز باشد، چون هر بار که تابعی فراخوانی میشود، ارجاعی در حافظه ذخیره میشود، جایی که ماشین مجازی باید نتیجه را برگرداند (روی پشتهی فراخوانی). اگر یک تابع بازگشتی خودش را بیپایان فراخوانی کند، ممکن است حافظه تمام شود و ماشین مجازی از کار بیفتد (یک خطای سرریز پشته). ماشین مجازی Erlang که Elixir روی آن اجرا میشود، بهطور ویژه برای بازگشت و پایداری بهینه شده است، بنابراین ممکن است زمان زیادی طول بکشد تا خطاهای بازگشت بیپایان آشکار شوند یا خرابی رخ دهد.
این مشکل اجرای بیپایان میتواند به این دلایل ایجاد شود: