Displaying articles with tag flip flop

Two-dots and Three-dots in Ruby

Posted by PunNeng, Wed Jul 26 17:28:00 UTC 2006

AMp เขียนครับ

วันนี้ ขอ off-rails หน่อยนะครับ ขอพูดถึง ruby เพียวๆ บ้าง

ใน ruby นั้น มีเครื่องหมาย two-dots และ three-dots ให้ใช้กัน two-dot ก็ จุดสองจุด เช่น 1..2 หรือ 5..8 เป็นต้น เป็นตัวที่เอาไว้บอก range ของค่า เช่น

a = (5..8).to_a

แบบนี้ก็จะได้ array ที่เป็น [5, 6, 7, 8]
ส่วนถ้าเป็น Three-dots ก็จะเป็นจุดสามจุด มีความหมายเหมือนกับ Two-dots เพียงแต่จะไม่สนใจค่าที่มากที่สุดที่เราระบุลงไป เช่น

a = (5...8).to_a

แบบนี้ก็จะได้ array ที่เป็น [5, 6, 7] ไม่รวม 8 นะครับ

พื้นฐานง่ายๆ แค่นี้ มาบอกกันทำไม?
....ถ้ามันเป็น range อย่างเดียว คงไม่มีปัญหาครับ

ในหนังสือ Programming Ruby มีกล่าวถึงเรื่อง two-dots และ three-dots ในหัวข้อ Ranges in Boolean Expressions ด้วย ซึ่งแน่นอนว่า ค่าที่ได้ หรือการทำงานของ two-dots และ three-dots ในเรื่องของ boolean expression นั้น จะต่างกันออกไป

ตัวอย่างที่หนังสือเล่มนี้แสดงให้ดู เป็นดังนี้ครับ

  1
  2
  3
  4
  5
a = (11..20).collect {|i| (i%4 == 0)..(i%3 == 0) ? i : nil}
# ผลลัพธ์คือ [nil, 12, nil, nil, nil, 16, 17, 18, nil, 20]

a = (11..20).collect {|i| (i%4 == 0)...(i%3 == 0) ? i : nil}
# ผลลัพธ์คือ [nil, 12, 13, 14, 15, 16, 17, 18, nil, 20]

ส่วนที่เราสนใจ ไม่ใช่ (11..20) นะครับ แต่เป็น (i%4 == 0)...(i%3 == 0) ? i : nil ต่างหาก จากตัวอย่าง จะเห็นว่ามีการใช้ทั้ง two-dot และ three-dot แต่ว่าผลลัพธ์กลับแตกต่างกันออกไป

การทำงานของทั้ง two-dots และ three-dots นั้น จะมีคอนเส็บเดียวกับ Flip-Flop นะครับ คือ จะมีการเปลี่ยน state เมื่อมีการทริก (expression = true) เกิดขึ้น

ต้องขอย้ำนะครับ ว่าเหมือนกับ Flip-Flop แค่ คอนเส็บ เท่านั้นนะครับ ไม่ได้เหมือนกันทางด้าน logic แต่อย่างใด (ทีแรกผมเอง ก็นึกว่า logic จะเหมือนกัน แต่ดูไปดูมาแล้ว จะเหมือนกันแค่คอนเส็บอย่างเดียว)

การใช้ range ใน boolean expression นั้น เราจะมอง range ให้เป็น state machine ซะก่อน (ถ้าใครไม่เข้าใจเรื่อง flip-flop ก็ขอให้มองเป็น ก้อนอะไรซักก้อนนึง - ยกเว้นก้อนอึ) ซึ่ง state machine นี้จะมีสองสถานะ คือ set และ unset และสถานะนี้จะเปลี่ยนได้ ก็ต่อเมื่อ expression ใน range เป็น true

สถานะของ state machine จะมีผลต่อค่าที่ return ออกมา โดยหาก state machine มี state = set ผลลัพธ์ก็จะเป็น true นอกนั้นจะเป็น false

ลำดับการเปลี่ยน state มีดังนี้ครับ State transitions

จากคำสั่ง (i%4 == 0)...(i%3 == 0) เราจะมองว่า ทางด้านซ้ายคือ expr1 และทางด้านขวา คือ expr2 นะครับ

เริ่มต้น state machine จะเป็น unset ก่อน เมื่อมีการ call range expression เกิดขึ้น และ state ในขณะที่ call เป็น unset จะมีการเช็คว่า expr1 เป็น true หรือไม่ ถ้าเป็น true จะมีการเปลี่ยน state เป็น set ทันที ซึ่งใน two-dots นั้น จะเพิ่มเรื่องการเช็ค expr2 หลังจากที่มีการเปลี่ยน state เป็น true แล้ว (ในการ call range expression ครั้งนั้นๆ) โดยหาก expr2 ยังเป็น true อีก ก็จะมีการเปลี่ยน state อีกครั้ง ทำให้ state machine ของเราตอนนี้ มี state เป็น unset เหมือนเดิม แต่ range expression ก็ยังคืนค่าเป็นtrue เหมือนเดิมนะครับ

และหากมีการ call range expression ในขณะที่ state เป็น set จะมีการเ็ช็คว่า expr2 มีค่าเป็น true หรือไม่ หากเป็น true ก็จะเปลี่ยน state เป็น unset แต่ range expression ก็ยังคืนค่าเป็น true เหมือนเดิม

แต่ถ้า expr ที่เช็ค (ทั้ง 1 และ 2) เป็น false ก็จะไม่มีการเปลี่ยน state ใดๆ ทั้งสิ้น และ range expression ก็จะ return ค่าเป็น false ด้วย

ลองไล่ตามตัวอย่างด้านล่างนี้นะครับ
two-dots table

สำหรับในกรณีของ three-dots นั้น จะต่างกับ two-dot นิดนึง ตรงที่ ในขณะ state = unset แล้ว expr1 = true จะไม่มีการเช็ค expr2 ต่อเหมือนใน two-dots ครับ แต่จุดต่างแค่นี้ ก็ทำให้ผลลัพธ์ต่างกันได้ ลองไล่ดูตารางข้างล่างนี้นะครับ three-dots table

ถ้าถามว่า ranges in boolean expression เอาไปทำอะไรได้ ก็ตอบได้ทันทีเลยครับว่า ผมก็ไม่รู้เหมือนกัน - -*

เพราะดูเหมือนว่าจะหาโอกาสเอาไปใช้ได้น้อยเหลือเกิน ตามปกติแล้ว เราก็ไม่ค่อยใช้วิธีเซ็ตสถานะด้วยวิธีทาง logic อยู่แล้ว (ถ้ามี ก็อาจจะเก็บเป็น flag ในตัวแปร ไปเลย ซึ่งจะใช้งานได้กว้างกว่า)

เอาเป็นว่า งานนี้ ถือว่าประดับสมองก็แล้วกันนะครับ ให้รู้กันไว้ว่า อีแบบเนี้ยะ ruby มันก็ทำได้ แต่จะเอาไปทำอะไรนั้น ช่างหัวมันเหอะครับ - -' (ใครมีไอเดีย บอกๆ กันมั่งก็ดีครับ)

ขอบคุณเหน่ง สำหรับคติประจำใจ กินไม่ได้ แต่เท่ ที่ำทำให้ผมพยายามเข้าใจมันจนได้ (แล้วมันเท่ตรงไหนฟะ - -*)

แก้ไขล่าสุด วันที่ 8 กรกฏาคม 2550 เวลา 21.55 น.

0 comments | Filed Under: Ruby | Tags: flip flop

codegent: we're hiring