วงแหวนเว็บ

neizod's speculation

insufficient data for meaningful answer

ตรรกะและการเขียนโค้ดจากวลี not all

Monday, August 22, 2022, 03:36 PM

พักหลังมานี้เรามักพบเห็นการระบายความคับข้องใจผ่านพื้นที่สาธารณะอยู่บ่อยครั้ง แน่นอนว่าคำพูดเหล่าเมื่อไม่ได้อยู่ในวงจำกัด มันก็จะสร้างความไม่สบายใจให้กับคนแปลกหน้าที่หลงทางแวะเวียนเข้ามารับสารได้ จนเกิดเป็นนวัตกรรมคำสร้อย “not all” เพื่อจำกัดปริมาณคนที่จะตีตนเข้าไปรับคำผรุสวาทเหล่านั้น (อารมณ์ประมาณข้อความปฏิเสธความรับผิดชอบในเอกสารทางกฎหมายนั่นแหละ)

อย่างเช่นประโยคว่า “men are trash (not all)” ที่แปลได้ว่า “ผู้ชายนั้นเหี้ย (ไม่ทุกคน)” ถ้าตีความโดยมองว่ามันเป็นคำพูดแบบที่เราใช้ทั่วไปในชีวิตประจำวัน ก็แปลได้ว่าในสังคมนั้นมีผู้ชายที่ดีและแย่ปนๆ กันไป ไม่ใช่ว่าผู้ชายทุกคนจะแย่ไปหมด แต่ก็ไม่ได้แปลว่าผู้ชายทุกคนจะดีไปหมด

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

\[\neg \forall m \; \text{Trash}(m)\]

โดยที่เอกภพสัมพัทธ์ที่สนใจคือเซตของผู้ชายทั้งหมด และ $\text{Trash}$ เป็นภาคแสดง (predicate) ที่จะบ่งว่าผู้ชายคนหนึ่งๆ นั้นเป็นขยะจริงหรือไม่

แล้วประโยคข้างต้นนี้บอกอะไรเราได้บ้าง? ลองสมมติดูว่าเซตเอกภพสัมพัทธ์มีผู้ชายอยู่สิบคน ในสิบคนนี้จะมีพวกขยะกี่คนก็ได้ แต่ต้องไม่ถึงสิบคน เพราะถ้าทั้งสิบคนนั้นเป็นขยะ นั่นหมายความว่าประโยคข้างต้นจะกลายเป็น $\forall m\; \text{Trash}(m)$ จึงเกิดเป็นข้อขัดแย้งนั่นเอง

แปลว่าจริงๆ แล้ว $\neg \forall m \; \text{Trash}(m)$ นั้นรับประกันว่าจะต้องมีผู้ชายอย่างน้อยหนึ่งคนแน่ๆ ที่ไม่ใช่ขยะ หรือก็คือมันสมมูลกับประโยคนี้

\[\exists m \; \neg \text{Trash}(m)\]

นั่นหมายความว่าเราสามารถกลับด้านตัวบ่งปริมาณได้ แต่ก็ต้องอย่าลืมกลับด้านภาคแสดงด้านในด้วย

จุดที่น่าสังเกตก็คือถึงแม้ $\neg \forall m \; \text{Trash}(m)$ จะไม่อณุญาตให้ผู้ชายเป็นขยะไปทั้งหมด แต่ในทางกลับกันนั้นผู้ชายทุกคนจะไม่ใช่ขยะเลยแม้แต่คนเดียวก็ได้ … ลองนึกตัวอย่างตามง่ายๆ ก็คือพิจารณาเอกภพสัมพัทธ์ที่มีแค่ผู้ชายคนเดียวดูสิ!

เพราะงั้นเวลาที่ได้ยินใครบ่นว่า “men are trash (not all)” ใจจริงลึกๆ แล้วเค้าอาจจะกำลังมองโลกในแง่ดีอยู่ว่า ผู้ชายทุกคนสามารถนั้นเป็นคนดีทั้งหมด ก็ได้นะ 😉


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

ถ้าเราเริ่มคิดจากที่ว่าเอกภพสัมพัทธ์เป็นเซตว่าง ก็จะติดหล่มว่าในเมื่อไม่มีสมาชิกแล้วจะไปทดสอบความจริงของประโยคดังกล่าวได้อย่างไร … จริงๆ แล้วเราอาจเริ่มคิดจากที่ว่าเอกภพสัมพัทธ์มีสมาชิกอยู่ $n$ ตัวก่อนก็ได้ ซึ่งเมื่อกระจายพจน์จะได้ว่า

\[\neg \forall m {\in} \lbrace m_1,m_2,\cdots,m_n\rbrace \left[\; \text{Trash}(m) \;\right] \equiv \neg \left( \text{Trash}(m_1) \wedge \text{Trash}(m_2) \wedge \cdots \wedge \text{Trash}(m_n) \right)\]

หรือก็คือการกระจายตัวบ่งปริมาณ $\forall$ จะทำให้ได้หลายๆ พจน์ที่เชื่อมกันด้วย $\wedge$ งั้นคำถามก็คือถ้าเราบีบให้ $n=0$ แล้วค่าที่ได้จากตัวดำเนินการ $\wedge$ ที่ทำกันเป็นจำนวนศูนย์ครั้งควรจะมีค่าเป็นอะไร?

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

ซึ่งเอกลักษณ์ของตัวดำเนินการ $\wedge$ ก็คือ $\top$ (เป็นจริง) ดังนั้น

\[\neg \forall m {\in} \emptyset \left[\; \text{Trash}(m) \;\right] \equiv \neg \top \equiv \bot\]

อนึ่ง เราอาจคิดในอีกทาง (ที่ง่ายกว่า?) ก็ได้ โดยระลึกว่าประโยคดังกล่าวนั้นให้ข้อจำกัดว่า ต้องมีผู้ชายอย่างน้อยหนึ่งคนที่ไม่เป็นขยะ จึงจะทำให้มันเป็นจริง แต่ในเมื่อเราไม่มีสมาชิกแม้แต่คนเดียวในเซตที่เราสนใจ จึงทำให้ข้อจำกัดดังกล่าวไม่มีทางเป็นไปได้ และได้ข้อสรุปเช่นเดียวกันว่า $\neg \forall m{\in}\emptyset \left[\; \text{Trash}(m) \;\right] \equiv \bot$ นั่นเอง


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

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

def available(doctors):
    return not all(busy(d) for d in doctors)

หรือเขียนแบบนี้ก็ได้เพราะสมมูลกัน

def available(doctors):
    return any(not busy(d) for d in doctors)

ซึ่งการเขียนทั้งสองแบบนั้นสั้นกระชับกว่าการเขียนโค้ดแบบดั้งเดิม (แต่ก็ยังสมมูลกันอยู่ดี)

def available(doctors):
    for d in doctors:
        if not busy(d):
            return True
    return False

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

neizod

author