Erlang Complex Data Structures

ในเอิร์ลแลง(Erlang)โครงสร้างข้อมูลที่ซับซ้อนหมายถึงการนำโครงส้างข้อมูลแบบพื้นฐาน ไม่ว่าจะเป็นอะตอม ลิสท์ ทัปเปิล และอื่นๆมาประกอบรวมกันเพื่อจำลองข้อมูลที่ซับซ้อนบางอย่าง เช่นเราต้องการสร้าง person ให้เป็นโครงสร้างที่ซับซ้อนที่ประกอบไปด้วย ชื่อ นามสกุล สัตว์เลี้ยง ความชื่นชอบ หรือ อื่นๆ จะได้ออกมาประมาณนี้
[{person,"Joe","Armstrong",
    [ {shoeSize,42},
        {pets,[{cat,zorro},{cat,daisy}]},
        {children,[{thomas,21},{claire,17}]}]},
 {person,"Mike","Williams",
    [ {shoeSize,41},
        {likes,[boats,wine]}]}
]

หรือถ้าเราต้องการสร้าง person ขึ้นมาแบบค่อยเป็นค่อยไปทีละขั้น ด้วยการใช้โครงสร้างพื้นฐานก็ทำได้แต่ผลที่ออกมาจะดูอ่านยากมาก

1> JoeAttributeList = [{shoeSize,42}, {pets,[{cat, zorro},{cat,daisy}]},
1> {children,[{thomas,21},{claire,17}]}].
        [{shoeSize,42},
            {pets,[{cat,zorro},{cat,daisy}]},
            {children,[{thomas,21},{claire,17}]}]
2> JoeTuple = {person,"Joe","Armstrong",JoeAttributeList}.
        {person,"Joe","Armstrong",
            [{shoeSize,42},
                {pets,[{cat,zorro},{cat,daisy}]},
                {children,[{thomas,21},{claire,17}]}]}
3> MikeAttributeList = [{shoeSize,41},{likes,[boats,wine]}].
        [{shoeSize,41},{likes,[boats,wine]}]
4> MikeTuple = {person,"Mike","Williams",MikeAttributeList}.
        {person,"Mike","Williams",
            [{shoeSize,41},{likes,[boats,wine]}]}
5> People = [JoeTuple,MikeTuple].
        [{person,"Joe","Armstrong",
            [{shoeSize,42},
                {pets,[{cat,zorro},{cat,daisy}]},
                {children,[{thomas,21},{claire,17}]}]},
         {person,"Mike","Williams",
            [{shoeSize,41},{likes,[boats,wine]}]}]

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

Erlang Pattern Matching
การเปรียบเทียบรูปแบบ(Pattern Matching)ใน Erlang ใช้สำหรับงานเช่น
• การกำหนดค่าให้ตัวแปร
• การควบคุมการทำงานของโปรแกรม
• การดึงค่าออกมาจากข้อมูลที่ถูกประกอบกันขึ้นมา(compound)

การเปรียบเทียบรูปแบบสามารถเขียนได้ในรูปนี้

    รูปแบบ(Pattern) = นิพจน์(Expression)

ตัว รูปแบบ(Pattern)นั้นจะประกอบไปด้วยตัวแปรที่ถูกผูก(bound)และตัวแปรที่ยัง ไม่ถูกผูก(unbound) รวมทั้งประเภทข้อมูลพื้นฐานต่างๆเช่น อะตอม อินทิเจอร์ และ สตริง 

    Double
    {Double, 34}
    {Double, Double}
    [true, Double, 23, {34, Treble}]

นิพจน์(Expression)ประกอบไปด้วยประเภทของข้อมูลต่างๆ, ตัวแปรที่ถูกผูกแล้ว, ตัวดำเนินการทางคณิตศาสตร์, การเรียกฟังก์ชั่น (ไม่สามารถใช้ ตัวแปรที่ยังไม่ถูกผูก ได้) เมื่อเราเห็นภาพแล้วว่าสิ่งที่อยู่ทั้งสองด้านของการทำการเปรียบเทียบรูปแบบ เราก็ควรจะรู้ว่าอะไรจะเกิดขึ้นเมื่อตัวเปรียบเทียบรูปแบบเริ่มทำงาน ผลของการทำงานมีสองแบบคือ

• การเปรียบเทียบสำเร็จ ส่งผลให้เราสามารถผูกค่าเข้ากับตัวแปรได้ และส่งค่านั้นกลับไป
• การเปรียบเทียบล้มเหลว ไม่มีก่ารผูกค่าเข้ากับตัวแปรใดๆเลย

แล้วเราจะรู้ได้อย่างไรว่าการเปรียบเทียบของเราสำเร็จหรือไม่? ก่อนอื่นเราต้องเข้าใจกระบวนการทำงานก่อน โดยที่การทำงานจะเริมจากการตรวจสอบนิพจน์ที่อยู่ทางขวามือก่อนที่จะทำการ เปรียบเทียบค่าของมันกับรูปแบบ(Pattern)ทางซ้ายมือ โดยจะมีกฎการเปรียบเทียบอยู่สี่ข้อคืด

• ทั้ง นิพจน์และตัวรูปแบบจะต้องมีลักษณะเหมือนกันเช่นทัปเปิลจะต้องมีจำนวนอิลิเมน ท์เท่ากันเท่านั้น ลิสท์ที่มีเทอมเป็น [X|Xs] จะต้องถูกเทียบกับลิสท์ที่ไม่เป็นลิสท์ว่างเท่านั้น 
• The literals in the pattern have to be equal to the values in the corresponding place in the value of the expression. 
• ตัวแปรที่ยังไม่ถูกผูกจะโดนผูกเข้ากับค่า ก็ต่อเมื่อกระบวนการเปรียบเทียบรูปแบบทำได้สำเร็จ
• ตัวแปรที่ถูกผูกแล้วจะต้องมีค่าเหมือนกับที่ที่มันผูกไว้ของนิพจน์ทางด้านขวา

ตัวอย่าง, ลองเขียน Sum = 1+2 โดยที่ตัวแปรที่ยังไม่ถูกผูกอย่าง Sum จะถูกใช้เพื่อผูกเข้ากับผลของการบวก 1 กับ 2 กระบวนการคือ Erlang จะบวก 1 กับ 2 ก่อนแล้วหลังจากนั้นจะไปตรวจดู Sum ว่าเป็นตัวแปรแบบที่ยังไม่ถูกผูกหรือไม่ถ้าใช่มันจะใส่ค่า 3 ให้กับ Sum เพราะเงือนไขการเปรียบเทียบรูปแบบ ถูกต้อง ในทางกลับกันถ้า Sum ถูกผูกแล้ว Sum จะไม่ถูกกำหนดค่าใหม่เพราะผลการเปรียบเทียบล้มเหลว กรณีเดียวที่การเปรียบเทียบจะสำเร็จโดยที่ Sum ถูกผูกแล้วก็คือ Sum จะต้องมีค่าเป็น 3 มาก่อนแล้วเท่านั้น
อีกตัวอย่าง

1> List = [1,2,3,4].
[1,2,3,4]

กรณีนี้การเปรียบเทียบจะสำเร็จ List จะมีค่าเป็น [1,2,3,4] 
ตัวอย่างต่อไป:

2> [Head|Tail] = List.
[1,2,3,4]
3> Head.
1
4> Tail.
[2,3,4]
กรณีนี้ก็สำเร็จเช่นกันเพราะไม่มีการเปรียบเทียบกับ ลิสท์ว่าง 
ตัวอย่างต่อไป

5> [Head|Tail] = [1].
** exception error: no match of right hand side value [1]
6> [Head|Tail] = [1,2,3,4].
[1,2,3,4]
7> [Head1|Tail1] = [1].
[1]
8> Tail1.
[]

เกิดอะไรขึ้นกับคำสั่งที่ 5 ? มันเหมือนจะไม่มีปัญหาอะไร แต่!!! [Head|Tail] ถูกผูกเข้ากับ [1,2,3,4] เรียบร้อยแล้วดังนั้นเมื่อเราพยายามจะถูกมันเข้ากับ [1] มันจะเอา [1] ไปเทียบกับ [1,2,3,4] และแน่นอนว่ามันไม่เท่ากันทำให้การเปรยบเทียบล้มเหลว แต่ถ้าเราใช้คำสั่งที่ 6 การเปรียบเทียบจะสำเร็จ ดังนั้นถ้าเราต้องการดึงเอาค่าออกมาจากลิสท์ [1] เราจำเป็นต้องใช้ลิสท์อีกตัวที่ยังไม่ถูกผูกค่าไว้

9> {Element, Element, X} = {1,1,2}.
{1,1,2}
10> {Element, Element, X} = {1,2,3}.
** exception error: no match of right hand side value {1,2,3}

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

11> {Element, Element, _} = {1,1,2}.
{1,1,2}

ต่อ ไปคือเรื่องสัญลักษณ์แบบเปิด(wildcard symbol), _ , ผลของมันคือมันจะถูกผูกเข้ากับอะไรก็ตามที่ยังไม่ถูกผูก ดังตัวอย่าง (นิยมใช้ในการดึงข้อมูลออกมาจากลิสท์ที่มีขนาดใหญ่มากและเราต้องการดึงบางอิ ลิเมนท์ออกมา)

12> {person, Name, Surname} = {person, "Jan-Henry", "Nystrom"}.
{person,"Jan-Henry","Nystrom"}
13> [1,2,3] = [1,2,3,4].
** exception error: no match of right hand side value [1,2,3,4]

วุ่นวาย ไหมครับ แล้วทำไมเราต้องใช้การเปรียบเทียบรูปแบบ? อันดับแรกคือเอาไว้กำหนดค่าให้ตัวแปร ใน Erlang ถ้าเราทำ Int = 1 การทำงานคือมันจะเปรียบเทียบค่าที่อยู่ในตัวแปร Int กันอินทิเจอร์ 1 ในกรณีที่ Int ยังไม่ถูกผูกมันจะถูกผูกเข้ากับค่าอะไรก็ตามที่อยู่ทางขวามือ นี่เป็นกระบวนการการกำหนดค่าให้ตัวแปรซึ่งจริงมันไม่ได้กำหนดค่าตรงๆแต่มัน จะทำการเปรียบเทียบรูปแบบตัวแปรนั่นเองนั่นเอง  ต่อไปให้เราเขียน Int = 1 และตามด้วย  Int = 1+0 ขั้นแรกทำการผูก Int เข้ากับ 1 หลังจากนั้นจะทำการบวก 0 เพิ่มเข้าไปกับ 1 แล้วทำการเปรียบเทียบค่าที่ได้กับค่าที่ผูกอยู่กับ Int ซึ่งแน่นอนมันจะเท่ากันทำให้ผลของการทำการเปรียบเทียบรูปแบบถูกต้อง ในทางกลับกันถ้าเราเปลี่ยนคำสั่งที่สองเป็น Int = Int +1 ผลที่ได้คือการเปรียบเทียบจะล้มเหลวเนื่องจาก 2 จะไม่เท่ากับค่าที่ผูกอยู่กับ Int ที่มีค่าเป็น 1

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

{A, A, B} = {abc, def, 123}

การเปรียบเทียบแบบแรกเราจะพิจรณาก่อนว่าทัปเปิลทั้งสองมีขนาดเท่ากันหรือไม่ ในที่นี้มันมีขนาดเป็นสามเท่ากันดังนั้นขั้นแรกสำเร็จ ต่อไปคือการเปรียบเทียบในระดับอิลิเมนท์ โดยที่ A = abc ก่อนแล้ว A ตัวที่สองจะถูกเปรียบเทียบกับ def ซึ่งจริงๆแลอ้วค่าเริ่มต้านของ A คือ abc ดังนั้นเมื่อเราพยายามเทียบกับ def ผลที่ได้จึงล้มเหลว
การเปรียบเทียบรูปแบบ [A,B,C,D] = [1,2,3] จะล้มเหลวถึงแม้ว่าทั้งสองฟากจะเป็นลิสท์เหมือนกันแต่จำนวนอิลิเมนท์ของทั้ง สองฝั่งนั้นไม่เท่ากันเพราะทางซ้ายมีสี่ตัวแต่ทางขวามีสามตัว แต่บางคนอาจจะสงสัยว่า แล้ว D ไม่ใช่ลิสท์ว่างหรือ? ความจริงคือเนื่องจากเครื่องหมายที่เราใช้แบ่งระหว่างอิลิเมนท์ C กับ D คือ , ไม่ใช่เครื่องหมาย cons ทำให้ D ไม่สามารถเป็นลิสท์ว่างได้ แต่ถ้าเราเขียนใหม่เป็น [A,B, C|D] = [1,2,3] การเปรียบเทียบรูปแบบจะสำเร็จ โดยที่ A,B,C จะมีค่าเป็น 1,2,3 ส่วน D จะถูกผูกเข้ากับลิสท์ว่างอัตโนมัติ เรามาลองอีกตัวอย่าง [A, B|C] = [1,2,3,4,5,6,7] ผลที่ได้คือ A กับ B จะมีค่าเป็น 1 และ 2 ตามลำดับส่วน C จะถูกผูกเข้ากับ [3,4,5,6,7] กรณีที่เราเขียน [H|T] = [] ผลที่ได้คือล้มเหลวเพราะเราไม่รู้จะเปรียบเทียบ H กับอะไรเนื่องจากอีกด้านเป็นลิสท์ว่าง สุดท้ายเรามาลองดึงเอาค่าออกมาจากข้อมูลแบบประกอบ(compound data types)

{A, _, [B|_], {B}} = {abc, 23, [22, 23], {22}}

ผลการเปรียบเทียบคือสำเร็จ A จะถูกผูกเข้ากับอะตอม abc ส่วน B จะถูกผูกเข้ากับอินทิเจอร์ 22

14> Var = {person, "Francesco", "Cesarini"}.
{person, "Francesco", "Cesarini"}
15 {person, Name, Surname} = Var.
{person, "Francesco", "Cesarini"}

เราตั้งใจจะดึงเอาค่าต่างๆในทัปเปิลที่ใช้ชื่อแทคว่า person ออกมาเก็บไว้ในทัปเปิลอีกตัวซึ่งผลที่ได้คือ Name จะได้ค่า "Francesco" ส่วน Surname จะได้ค่า "Cesarini" ในเรื่องการดึงค่าออกมาจากลิสท์หรือทัปเปิลนั้นที่นิพจน์ที่อยู่ทางซ้ายมือ ตัวแปรต่างๆสามารถขึ้นต้นได้ด้วย _ ซึ่งจะหมายถึง "ไม่สนใจ" เครื่องหมายนี้มักถูกใช้กับค่าที่เราไม่สนใจแต่ตัวมันเองมีพฤติกรรมเหมือน กับตัวแปรทั่วๆไปเช่นเราสามารถนำมันมาเปรียบเทียบ ตรวจสอบ และนำไปใช้งานได้ การใช้ตัวแปรแบบ "ไม่สนใจ" นี้ถือว่าเป็นข้อปฎิบัติที่ดีของการเขียนโปรแกรมบนErlang เนื่องจากคนที่มาอ่านโปรแกรมต่อจากเราจะได้แยกแยะได้ว่าบริเวณไหนที่เขาไม่ ต้องสนใจ ยกตัวอย่างเช่น

{A, _, [B|_], {B}} = {abc, 23, [22, 24], {22}}

จะเห็นว่า _ จะไม่ถูกผูกเข้ากับค่าอะไรเลยและมันก็ไม่สนใจด้วยว่าค่าอะไรที่เรากำลัง เปรียบเทียบอยู่ แต่ในทางกลับกันถ้าเราเขียนอีกแบบ

{A, _int, [B|_int], {B}} = {abc, 23, [22, 24], {22}}

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


edit @ 15 Dec 2009 11:02:03 by cyber-climber

edit @ 15 Dec 2009 11:05:36 by cyber-climber

edit @ 16 Dec 2009 13:22:53 by cyber-climber

Comment

Comment:

Tweet

You are desperate and have no idea how to complete your Economics Essay "perfectwritings.com", order it from the most trustful agency and you will never feel sorry.

#7 By Book Review Essay (31.184.238.73) on 2013-08-19 09:50

Your blog information is highly developed.I like your information detail.Nice post.keep it up..

#6 By Best forum hosting (115.119.115.38) on 2012-03-16 16:31

The best thesis report referring to this topic made by thesis writing service or dissertations writing service will be a proper point to the academic success.

#5 By IsabelWilder25 (91.212.226.143) on 2011-11-19 18:01

ขอบตคุณสำหรับเนื้อหาดีดี เกี่ยวกับ Erlang.

#4 By jamjam (124.121.122.174) on 2010-09-08 23:39

นู๋โบ๊ทงงครับ

#3 By nuboat (180.210.216.68) on 2010-01-10 19:50

ขอบคุณครับ...ผมคงต้องขอเข้ามาอ่านหลายๆ รอบครับ.

#2 By @mnk2551 (58.8.35.243) on 2009-12-17 15:21

ตอนนี้เป็นตอนที่งงมากๆ
เดี๋ยวต้องไปลองดูเองก่อนครับ
จะได้เข้าใจขึ้น

รออ่านตอน 8 ต่อครับ meeting จะได้มีอะไรไปถามเยอะๆ big smile

#1 By iporsut (58.9.55.99) on 2009-12-15 23:58