Monthly Archives: June 2016

เลือกพฤติกรรมของฟังก์ชันด้วยพารามิเตอร์ฟังก์ชัน

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

ผมขอยก merge-with ขึ้นมาเป็นตัวอย่างเพื่ออธิบาย
 
Clojure มีฟังก์ชัน merge ที่ใช้รวม map มากกว่า 2 อันเข้าด้วยกัน โดยหากมี key ที่ซ้ำกันระหว่าง map จะทำการใช้ value จาก map อันสุดท้าย

แต่การเลือกเอาค่าสุดท้ายไม่ได้เป็นสิ่งที่เราต้องการเสมอไป Clojure จึงมีฟังก์ชัน merge-with ให้เราเลือกใช้หากเราต้องการพฤติกรรมเมื่อมี key ซ้ำกันที่แตกต่างออกไปจาก merge ปกติ เช่น
เราสามารถเลือกรวม vector เช่นนี้ได้โดยใช้ concat ช่วย

(merge-with concat {:a [1 2 3]} {:a [4 5 6]})
;=> {:a (1 2 3 4 5 6)}
 หรือจะเลือกเอาค่าที่มากที่สุดโดยการส่ง max เข้าไป
 
(merge-with max {:a 1} {:a 3} {:a 2}) 
;=> {:a 3} 
นอกจากจะมีคู่ merge & merge-with แล้ว ฟังก์ชันอื่นๆ ด้านบนก็มีคู่ในลักษณะเดียวกัน partition & partition-by, split & split-with, assoc & update, assoc-in & update-in, sort & sort-by

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

หวังว่าตัวอย่างเหล่านี้จะช่วยเพิ่มความเข้าใจในประโยชน์ของ functional programming มากขึ้นนะครับ

Advertisements