Erlang - การเรียกซ้ำ

การเรียกซ้ำเป็นส่วนสำคัญของ Erlang ก่อนอื่นมาดูกันว่าเราจะใช้การเรียกซ้ำอย่างง่ายได้อย่างไรโดยใช้โปรแกรมแฟกทอเรียล

ตัวอย่าง

-module(helloworld). 
-export([fac/1,start/0]). 

fac(N) when N == 0 -> 1; 
fac(N) when N > 0 -> N*fac(N-1). 

start() -> 
   X = fac(4), 
   io:fwrite("~w",[X]).

สิ่งต่อไปนี้ต้องสังเกตเกี่ยวกับโปรแกรมข้างต้น -

  • ก่อนอื่นเราจะกำหนดฟังก์ชันที่เรียกว่า fac (N)

  • เราสามารถกำหนดฟังก์ชันการเรียกซ้ำได้โดยเรียก fac (N) แบบเรียกซ้ำ

ผลลัพธ์ของโปรแกรมข้างต้นคือ -

เอาต์พุต

24

แนวทางปฏิบัติในการเรียกซ้ำ

ในส่วนนี้เราจะทำความเข้าใจโดยละเอียดเกี่ยวกับการเรียกซ้ำประเภทต่างๆและการใช้งานใน Erlang

การเรียกซ้ำความยาว

แนวทางที่เป็นประโยชน์มากขึ้นในการเรียกซ้ำสามารถดูได้จากตัวอย่างง่ายๆซึ่งใช้เพื่อกำหนดความยาวของรายการ รายการสามารถมีได้หลายค่าเช่น [1,2,3,4] ลองใช้การเรียกซ้ำเพื่อดูว่าเราจะได้ความยาวของรายการได้อย่างไร

Example

-module(helloworld). 
-export([len/1,start/0]). 

len([]) -> 0; 
len([_|T]) -> 1 + len(T). 

start() -> 
   X = [1,2,3,4], 
   Y = len(X), 
   io:fwrite("~w",[Y]).

สิ่งต่อไปนี้ต้องสังเกตเกี่ยวกับโปรแกรมข้างต้น -

  • ฟังก์ชั่นแรก len([]) ใช้สำหรับเงื่อนไขกรณีพิเศษหากรายการว่างเปล่า

  • [H|T] รูปแบบเพื่อจับคู่กับรายการขององค์ประกอบตั้งแต่หนึ่งรายการขึ้นไปเนื่องจากรายการความยาวหนึ่งจะถูกกำหนดเป็น [X|[]] และรายการความยาวสองจะถูกกำหนดเป็น [X|[Y|[]]]. โปรดทราบว่าองค์ประกอบที่สองคือรายการเอง ซึ่งหมายความว่าเราจำเป็นต้องนับหนึ่งเท่านั้นและฟังก์ชันสามารถเรียกตัวเองในองค์ประกอบที่สองได้ กำหนดให้แต่ละค่าในรายการนับเป็นความยาว 1

ผลลัพธ์ของโปรแกรมข้างต้นจะเป็น -

Output

4

การเรียกซ้ำหาง

หากต้องการทำความเข้าใจว่าการเรียกซ้ำหางทำงานอย่างไรเรามาทำความเข้าใจว่าโค้ดต่อไปนี้ในส่วนก่อนหน้าทำงานอย่างไร

Syntax

len([]) -> 0; 
len([_|T]) -> 1 + len(T).

คำตอบของ 1 + len (Rest) ต้องการคำตอบของ len (Rest) จึงจะพบ ฟังก์ชั่น len (Rest) นั้นเองก็ต้องการผลลัพธ์ของการเรียกใช้ฟังก์ชันอื่น การเพิ่มจะซ้อนกันจนกว่าจะพบรายการสุดท้ายจากนั้นจะคำนวณผลลัพธ์สุดท้ายเท่านั้น

การเรียกซ้ำหางมีจุดมุ่งหมายเพื่อกำจัดการดำเนินการที่ซ้อนกันนี้โดยการลดจำนวนลงเมื่อเกิดขึ้น

เพื่อให้บรรลุเป้าหมายนี้เราจะต้องถือตัวแปรชั่วคราวพิเศษเป็นพารามิเตอร์ในฟังก์ชันของเรา ตัวแปรชั่วคราวดังกล่าวบางครั้งเรียกว่าตัวสะสมและทำหน้าที่เป็นที่เก็บผลลัพธ์ของการคำนวณของเราเมื่อเกิดขึ้นเพื่อ จำกัด การเติบโตของการโทรของเรา

ลองดูตัวอย่างของการเรียกหางซ้ำ -

Example

-module(helloworld).
-export([tail_len/1,tail_len/2,start/0]). 

tail_len(L) -> tail_len(L,0). 
tail_len([], Acc) -> Acc; 
tail_len([_|T], Acc) -> tail_len(T,Acc+1). 

start() -> 
   X = [1,2,3,4], 
   Y = tail_len(X), 
   io:fwrite("~w",[Y]).

ผลลัพธ์ของโปรแกรมข้างต้นคือ -

Output

4

ทำซ้ำ

ลองดูตัวอย่างของการเรียกซ้ำ คราวนี้เรามาเขียนฟังก์ชันที่ใช้เลขจำนวนเต็มเป็นพารามิเตอร์ตัวแรกจากนั้นคำอื่น ๆ เป็นพารามิเตอร์ที่สอง จากนั้นจะสร้างรายการสำเนาของคำศัพท์ตามที่ระบุโดยจำนวนเต็ม

มาดูตัวอย่างกันว่าจะเป็นอย่างไร -

-module(helloworld). 
-export([duplicate/2,start/0]). 

duplicate(0,_) -> 
   []; 
duplicate(N,Term) when N > 0 ->
   io:fwrite("~w,~n",[Term]),
   [Term|duplicate(N-1,Term)]. 
start() -> 
   duplicate(5,1).

ผลลัพธ์ของโปรแกรมข้างต้นจะเป็น -

เอาต์พุต

1,
1,
1,
1,
1,

รายการการกลับรายการ

ไม่มีขอบเขตที่คุณสามารถใช้การเรียกซ้ำใน Erlang ได้ มาดูกันอย่างรวดเร็วว่าเราสามารถย้อนกลับองค์ประกอบของรายการโดยใช้การเรียกซ้ำได้อย่างไร สามารถใช้โปรแกรมต่อไปนี้เพื่อทำสิ่งนี้ให้สำเร็จ

ตัวอย่าง

-module(helloworld). 
-export([tail_reverse/2,start/0]). 

tail_reverse(L) -> tail_reverse(L,[]).

tail_reverse([],Acc) -> Acc; 
tail_reverse([H|T],Acc) -> tail_reverse(T, [H|Acc]).

start() -> 
   X = [1,2,3,4], 
   Y = tail_reverse(X), 
   io:fwrite("~w",[Y]).

ผลลัพธ์ของโปรแกรมข้างต้นจะเป็น -

เอาต์พุต

[4,3,2,1]

สิ่งต่อไปนี้ต้องสังเกตเกี่ยวกับโปรแกรมข้างต้น -

  • เราใช้แนวคิดของตัวแปรชั่วคราวอีกครั้งเพื่อจัดเก็บแต่ละองค์ประกอบของรายการในตัวแปรที่เรียกว่า Acc

  • เราก็โทร tail_reverse วนซ้ำ แต่คราวนี้เรามั่นใจว่าองค์ประกอบสุดท้ายถูกใส่ในรายการใหม่ก่อน

  • จากนั้นเราจะเรียกใช้ tail_reverse ซ้ำสำหรับแต่ละองค์ประกอบในรายการ