Friday, October 08, 2004

นับและบวกลบเลขด้วย Prolog

กลับจากพักผ่อนมาทำงานวันแรก อ้าว วันนี้ไม่มีประชุม นึกๆอยู่ว่าจะทำอะไรแทนดี งานที่ยังไม่เสร็จก็มีมากโข หาอะไรเล่นก่อนดีกว่า

เคยเล่น Prolog สมัยอยู่ ม.ปลาย ตอนนั้น Turbo Prolog เพิ่งจะออกมา กำลังฮิต และมีบทความข่าวคราวเกี่ยวกับพวก Expert System เยอะ บรรยากาศ คือ คอมพิวเตอร์กำลังจะฉลาดขึ้น ยุคของ AI กำลังมา

บ้า Prolog อยู่พักนึง นานพอสมควรเพราะมีเพื่อนคู่หูสนิทคนนึงเล่นด้วยกัน ตกเย็นหรือเสาร์อาทิตย์ก็มานั่งอ่านหนังสือ Prolog มีกันคนละเล่ม เพื่อนคนนี้เรียกได้ว่าระดับอัจฉริยะคนนึง ไม่ได้สอบเทียบ หลังเรียนจนจบ ม.6 ก็ได้ทุนไปเรียนต่อวิศวะที่ญี่ปุ่น แต่เรียนได้สักพักเกิดเปลี่ยนใจอยากเป็นหมอ ก่อนผมมาญี่ปุ่นก็เจอกันหนหนึ่ง ตอนนั้นแกเพิ่งกลับไปพอดี กำลังเตรียมตัวสอบเอ็นท์หมอ

มาญี่ปุ่นได้ไม่นาน ได้ข่าว อ้าวพี่แกสอบเข้าได้ที่หนึ่งหมอจุฬาฯ แซงรุ่นน้องๆ ม.5-6 ปีนั้นเลย เห็นไหมละ เก่งจริงๆ ยังรื้อฟื้นวิชา ชีวะ ได้อีก (ของตัวเองคืนอาจารย์ไปหมดแล้ว) สรุปเลยมีเพื่อนร่วมห้องสอบเข้าได้ที่หนึ่งหมอจุฬาฯสองคน คนละปี

โม้เรื่องเพื่อนเสร็จแล้ว กลับมาเรื่องเดิม สรุปว่าวันนี้ว่าง (เพราะขี้เกียจทำงาน) ก็เลยลองเอา Prolog มาปัดฝุ่น ตั้งแต่เข้ามหาลัยก็ไม่ได้เล่น Prolog เลย จนปี 4 ปีสุดท้าย เอามาทำ Senior Project

ตอนนี้ Turbo Prolog ไม่รู้จะไปหาที่ไหนแล้ว พอดีบนเครื่อง WebLS ดูเหมือนอ็อตจะลง GNU Prolog เอาไว้ ลองเล่นตัวนี้ก็แล้วกัน

หลังจากอ่านคู่มืออยู่สักพัก ก็พอเข้าใจวิธีการใช้งาน ใครเคยอ่าน Prolog คงรู้ว่าภาษานี้ค่อนข้างจะแหวกแนว ไม่ได้ตรงไปตรงมาทำทีละคำสั่ง บนลงล่าง ซ้ายไปขวา เหมือน BASIC/C ฯลฯ แต่ทุกอย่างเขียนเป็น ขอเท็จจริง และ กฏ

บทที่หนึ่ง: นับเลข

วันนี้ บทเรียนแรก สอนให้มันนับเลขก่อนก็แล้วกัน

next(0,1).
next(1,2).
next(2,3).
next(3,4).
next(4,5).
next(5,6).
next(6,7).
next(7,8).
next(8,9).
เป็นการนิยามคำว่า next โดยให้ next ของ 0 คือ 1, next ของ 1 คือ 2 ฯลฯ จนถึง next ของ 8 คือ 9

สมมติว่าเอาโปรแรกมนี้เขียนใส่ไฟล์ชื่อ add.pro แล้วเรียกคำสั่ง prolog --query-goal "['add.pro']" จะได้

GNU Prolog 1.2.9
By Daniel Diaz
Copyright (C) 1999-2001 Daniel Diaz
| ?- ['add.pro'].
compiling /.../add.pro for byte code...
/.../add.pro compiled, 14 lines read - 1476 bytes written, 15 ms

(1 ms) yes
ตอนนี้ Prolog ก็รู้แล้วว่ามีเลขอะไร เป็น next กับเลขอะไรบ้าง เช่นอยากรู้ว่า next ของ 5 เป็นเท่าไร ก็ถามไปว่า next(5,A).
| ?- next(5,A).

A = 6

(1 ms) yes
ใน Prolog สายอักขระที่ขึ้นต้นด้วยอักษรใหญ่ เช่น A จะถือเป็นตัวแปร โปรแกรมจะพยายามหาค่ามาใส่ ตัวแปร เพื่อให้คำสั่งที่พิมพ์เข้าไป (next(5,A).) เป็น จริง โดยใช้ข้อมูลจากที่สอนไว้ ซึ่งพบว่าคำสั่งนี้จะเป็นจริงเมื่อ A=6

จะถามกลับกันก็ได้ เช่น

| ?- next(B,9).

B = 8

yes
หรือตรวจสอบว่าจริงหรือไม่จริง
| ?- next(7,6).

no
ถ้าถามในสิ่งที่ไม่รู้ ก็จะบอกว่า no เช่นกัน
| ?- next(12,A).

no
และสุดท้าย ตัวแปรอาจจะมีได้มากกว่าหนึ่งตัว
| ?- next(A,B).

A = 0
B = 1 ? a

A = 1
B = 2

A = 2
B = 3

A = 3
B = 4

A = 4
B = 5

A = 5
B = 6

A = 6
B = 7

A = 7
B = 8

A = 8
B = 9

yes
Prolog จะไปขุดมาให้หมดว่า จากความรู้ที่มีอยู่ มี A,B อะไรบ้างที่ทำให้ next(A,B). เป็นจริง

บทที่สอง: บวกลบเลข

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

เขียนกฏการบวกใน Prolog คล้ายกับการเขียน Recursive Function เริ่มจากกฏที่ตายตัวก่อน คือ 0 บวกอะไรก็เป็นตัวนั้น

add(0,X,X).
จากนั้นก็ คิดต่อว่าถ้าตัวแรกเป็นค่าถัดจาก 0 คือ 1 คำตอบก็เป็นค่าถัดจาก X เหมือนกัน ซึ่ง เขียนเป็นกฏได้ดังนี้
add(A,B,C) :- next(K,A), 
              add(K,B,L), 
              next(L,C).
คือ A บวก B จะเท่ากับ C ถ้าหากว่า มี K ซึ่งเป็นตัวก่อนหน้า A และ K บวก B เท่ากับ L และ C เป็นค่าถัดจาก L

ซึ่งสองกฏนี้ก็ดูเหมือนจะเพียงพอสำหรับการบวกเลข A, B, C ใดๆ ซึ่งมีค่า 0-9 แล้ว

| ?- add(3,4,A).

A = 7 

| ?- add(3,0,A).

A = 3 
เนื่องจาก Prolog จะพยายามหาค่าตัวแปรที่ทำให้คำสั่งเป็นจริง ก็เลยสามารถเปลี่ยนตำแหน่งตัวแปร ให้ หาผลลบได้ด้วยเช่นกัน
| ?- add(3,A,9).

A = 6 

| ?- add(A,7,8).

A = 1
และจะใส่หลายๆตัวแปรก็ได้ อะไรบ้างที่บวกกันได้ 8 ?
| ?- add(A,B,8).

A = 0
B = 8 ? a

A = 1
B = 7

A = 2
B = 6

A = 3
B = 5

A = 4
B = 4

A = 5
B = 3

A = 6
B = 2

A = 7
B = 1

A = 8
B = 0
หรือว่า อะไร บวก อะไร เป็นอะไร ได้บ้าง ?
| ?- add(A,B,C).

A = 0
C = B ? a

A = 1
B = 0
C = 1

...
A = 8
B = 1
C = 9

A = 9
B = 0
C = 9
เลขตัวเดียวกัน บวกกันเป็นอะไรบ้าง ? (หาคำตอบที่เป็นไปได้ของสมการ A+A=B โดยที่ A,B = 0...9)
| ?- add(A,A,B).

A = 0
B = 0 ? a

A = 1
B = 2

A = 2
B = 4

A = 3
B = 6

A = 4
B = 8
และสุดท้าย เลขอะไร ที่บวกตัวมันเอง แล้วเป็นตัวมันเอง ?
| ?- add(A,A,A).

A = 0 ? a
ถ้าขยายให้คำนวณหลายหลักได้ คงจะเอามาแก้ ปริศนาแทนตัวเลขด้วยอักษร ได้เหมือนกัน

ตัวโปรแกรม

add.pro

เพิ่มเติม

  • อาจใช้ตัวอักษรแทนตัวเลข คือ next(one,two) ได้เหมือนกัน เพื่อให้เห็นชัดเจนว่าเป็นการบอกความสัมพันธ์ของสองสิ่ง (ซึ่งไม่จำเป็นต้องเป็นตัวเลข)

  • สรุปว่า การบวกลบ ก็มาจาก การนับเลข

1 comment:

Wutikrai said...

หวัดดี

ผมก็เคยเล่น turbo prolog 2.0 มาก่อน ยังสนใจ AI แต่ยังไม่มีโอกาสศึกษามันต่อ
ตอนนี้สนใจจำนำมประยุกต์ กับ image processing เพื่อให้หุ่นยนต์ สามารถจำแนกวัตถุ และเดินหลบหลีกเองได้

สนใจร่วมค้นคว้าต่อใหม่?

วุฒิไกร