9/3(2+1) = ?
จะตอบโดยไม่ลังเลเลยว่า 1 แถมถ้าใครมาบอกว่าต้องคิดหารทางด้านซ้ายมือ แล้วค่อยมาคูณแบบคอมพิวเตอร์นะ จะตอบกลับไปเลยว่ามัน
syntax error
โว้ย ภาษาคอมพิวเตอร์ที่ไหนเค้ายอมรับการเขียนเลขติดกันว่าเป็นการคูณเลขบ้าง?อนึ่ง ถ้ามองว่าการเขียนเลขติดกัน (คั่นด้วยวงเล็บ) เป็นการคูณจริงๆ ตัวที่ติดกับวงเล็บก็ต้องมี precedence สูงกว่า (ทำงานก่อน) เครื่องหมายหารอยู่แล้ว นั่นหมายความว่าต้องคิดส่วน
3(2+1)
ให้เสร็จก่อนเอาไปคำนวณต่ออยู่ดีเจอบ่อยๆ ก็เริ่มขี้เกียจอธิบาย เลยเขียนโปรแกรมที่มันแปลสมการด้านบนนี้ได้ถูกต้องเลยละกัน -> จิ้มโลด
ตัวอย่างผลลัพท์จากโปรแกรม
>>> 9/3(2+1) 1.0 >>> a, b, c, d = 48, 2, 9, 3 >>> a/b(c+d) 2.0 >>> 10(9(8(7(6(5(4(3(2(1))))))))) 3628800 >>> (1+2j)(3-4j) (11+2j) >>> 1 + 1/phi 1.618033988749895 >>> phi(43) 42
อันที่จริงก็คิดว่าจะทำมาได้ซักพักละ แต่ด้วยความที่ขี้เกียจวางกฎ grammar ด้วย flex bison ทั้งที่หลายๆ กฎนั้นภาษาส่วนใหญ่ก็ทำไว้ให้แล้ว เลยดองมาเรื่อยๆ จนทำ Infinite List เสร็จ และไปเจอ Python's Magic Methods เลยได้ฤกษ์เริ่มจากตรงนั้น
แนวคิดก็ง่ายนิดเดียว แค่เพิ่มเมธอด
__call__
เข้าไปให้ class ของตัวเลข (เป็น Monkey Patching เหมือนใน Ruby) โดย define มันกว่าถ้าเรียก a.__call__(b)
แล้วจะมีค่าเท่ากับเอามันมาคูณกันซะปัญหาที่ต้องไล่เก็บก็คือ
- Python ไม่อนุญาติให้แก้ไขพวก
builtins
-- ที่จริงปัญหานี้ก็เหมือนกับคราวที่ทำ Infinite List นั่นแหละ ซึ่งแก้ไม่ยาก แค่ inherit class นั้นๆ ออกมาแล้วไล่ define magic method ซะ - ปัญหาจริงๆ คือ Python parser มันจะแปลตัวเลขไปเป็น class ตัวเลขใน
builtins
เท่านั้น ดังนั้นก็ต้องแปลง token เองโดยหาว่าตรงไหนคือเลข แล้วก็เอา class ตัวเลขที่ inherit มาแล้วครอบไว้ - งานนี้ได้โมดูล tokenize มาช่วยแปลตัวเลขให้ ไม่ต้องเขียน regex เอง เพราะมันจะมีท่าประกาศตัวเลขประหลาดๆ ทำให้ tokenize เองพลาดได้
- ที่เหลือก็เอา code ที่แก้ token เรียบร้อยไปทำงาน ตรงนี้ดึงโมดูล
code
ที่ทำทุกอย่างเตรียมไว้แล้วมาใช้ฟังก์ชันเดียวจบ - แต่ตอนที่เอา
tokenize
มาใช้ร่วมกับcode
จะมีปัญหาที่พิมพ์ได้ทีละบรรทัด เนื่องจากtokenize
มันปรับแต่งอะไรไม่ได้เลย ก็ต้องหลอกมันเอานิดหน่อย - ครบถ้วนกระบวนความแล้วก็ clean up โดยจุดที่เอา code ออกไปได้เยอะมากๆ คือส่วน define magic method อันนี้ใช้ meta-programming บอกแค่ว่าจะเพิ่ม method ไหนบ้างก็พอ แล้วปล่อยให้มัน generate ตัวเองไปซะ
- อยู่ๆ ก็เขียน function decorator เป็นเฉยเลย งงตัวเอง 555+
φ
(phi) ที่อาจหมายถึง golden radio หรือ Euler's totient ก็ได้ ซึ่งแม้ว่าทั้ง 2 รูปของ φ
นี้จะไม่ overlap กัน (เช่น 1+1/φ
จะถูกมองว่าเป็นตัวเลข ในขณะที่ φ(43)
คือการใช้ฟังก์ชัน) แต่ด้วยความที่ Python เป็น 1st class function ที่ยอมให้เราส่งผ่านฟังก์ชันเป็นตัวแปรของฟังก์ชันอื่นๆ ได้ ดังนั้นถ้าเราเจออะไรอย่าง δ(φ,ε)
เราจะไม่สามารถแน่ใจได้เลยว่า φ
ในบริบทนี้คืออะไรครับ