Basic Clojure Command
Clojure มี syntax ง่ายๆ คือวงเล็บเปิด ตามด้วยชื่อฟังค์ชันและ argument ต่างๆและจบด้วยวงเล็บปิด เช่นถ้าอยาก บวก ลบ คูณ หาร ง่ายๆ จะทำได้ดังนี้
operator เบื้องต้นของ Clojure ก็มีเหมือนกับ ภาษาอื่นๆทั่วๆ ยกตัวอย่าง บวก ลบ คุณ หาร เช่น
(+ 2 2)
;=> 4(- 4 1)
;=> 3(* 2 7)
;=> 14(/ 50 10)
;=> 5
ในที่นี้เครื่องหมาย + คือฟังค์ชันบวกนั่นเอง โดยรับ 2 2 เป็น argument เครื่องหมาย
- * และ / ก็เช่นเดียวกัน
ฟังก์ชันเหล่านี้ยังสามารถรับ argument ได้มากกว่า 2 ตัว เช่น
(+ 2 2 5 6)
;=> 15(- 4 1 5 4 7 9)
;=> -22(* 2 7 2 )
;=> 28(/ 50 5 2 )
;=> 5
สามารถใช้ฟังค์ชันซ้อนฟังค์ชันได้
(+ 5 (- 19 2 (* 2 2)))
;=> 18
สามารถเช็คเท่ากันได้ดังนี้
(= 1 1)
;=> true(= 2 1)
;=> false
คำสั่งนิเสธค่า
(not true)
;=> false
ต่อไปเราจะมาดูว่า หากเราต้องการประกาศตัวเเปร จะต้องทำยังไง
ใน Clojure เราใช้คำสั่ง def ดังต่อไปนี้
(def i 0)
หมายความว่าให้ ตัวเเปร i =0
หรือเราจะเขียนประยุกต์กับฟังค์ชันก็ได้ เช่น
(def i (+ 65 5))
i
;=> 70
ตัวเเปร i จะมีค่าเท่ากับ 70
ต่อไป เราจะมาดูการสร้าง list
list จะคล้ายๆ array เช่น
(list 1 2 3 4 5 6)
;=> (1 2 3 4 5 6)
คำสั่ง list จะสร้าง list ตาม argument ในที่นี้จะได้ list ที่มีข้อมูลเลข 1– 6 อยู่
หรือจะสร้างแบบนี้ก็ได้
‘(1 2 3 4 5 6)
;=> (1 2 3 4 5 6)
ต่อไปเราจะลองนำหลายๆคำสั่งมาผสมกัน
ในที่นี้จะลองใช้คำสั่ง apply เรามาดูตัวอย่างกันดีกว่า
(def i (apply + (list 1 2 5 7 8)))
i
;=> 23
หมายความว่า ให้ค่า i มีค่าเท่ากับค่าใน list ทั้งหมดบวกกัน
ต่อไป เราจะมาดูคำสั่ง range กัน
(range 1 10)
;=> (1 2 3 4 5 6 7 8 9)
หมายความว่าสร้าง list ตั้งเเต่ 1–9
มาลองดูตัวอย่างโจทย์โปรเเกรมง่ายๆกัน
จงเขียนโปรเเกรมที่ บวกเลขตั้งเเต่ 1–100 เราก็สามารถเขียนได้ดังนี้
(apply +(range 1 101))
;=> 5050
ในภาษาแบบ functional นั้น คำสั่งที่มีความสำคัญพอๆกับคำสั่ง for ในภาษาแบบ imperative คือคำสั่ง map ซึ่งทำงานดังนี้
(map inc ‘(1 2 3 4 5))
;=> (2 3 4 5 6)
map รับ argument ตัวแรกเป็นฟังค์ชัน ตัวถัดไปเป็น list ในที่นี้ฟังค์ชันที่โยนเข้าไปคือฟังค์ชั่น inc (เป็นฟังค์ชันที่เพิ่มค่าให้กับ argrument ไป 1) map จะนำสมาชิกแต่ละตัวใน list มาโยนให้ฟังค์ชัน inc ทำทีละตัว จากนั้นนำมารวมกันเป็น list อีกที
คำสั่ง filter รับ argument 2 ตัว ตัวแรกเป็นฟังค์ชัน ตัวต่อไปเป็น list ฟังก์ชัน filter จะกรอง list โดยจะโยนสมาชิกใน list แต่ละตัวไปทดสอบกับฟังค์ชัน หาก return false สมาชิกนั้นจะถูกนำออกจาก list เช่น
(filter even? (range 0 11))
;=> (0 2 4 6 8 10)
คำสั่ง even? ใช้ทดสอบว่าค่าเป็นเลขคู่หรือไม่ ถ้าเป็นจะ return true ถ้าไม่เป็นจะ return false
defn ใช้ในการประกาศฟังค์ชันใช้เอง เช่น
(defn square [x] (* x x))
(squrare 5)
;=> 25
ในที่นี้ประกาศฟังก์ชันชื่อ “square” แล้วรับ argument “x” โดยฟังค์ชันจะ return ค่า (* x x) ออกไป
fn ใช้ประกาศฟังค์ชันแบบ lambda (ฟังค์ชั่นที่ไม่มีชื่อ) มีตัวอย่างดังนี้
(fn [x] (* x x))
จะได้ฟังค์ชันที่ทำงานเหมือนฟังค์ชัน square และสามารถนำไปใช้ได้ดังนี้
((fn [x] (* x x)) 5)
;=> 25
เราสามารถใช้ fn กับฟังค์ชันอื่นๆที่รับ ฟังค์ชันเป็น argument ได้ เช่น
(map (fn [x] (+ x x)) ‘(1 2 3))
;=> (2 4 6)(filter (fn [x] (= x 2)) ‘(1 2 3))
;=> (2)
let เป็น special form ที่ช่วยให้เรา bind ค่าเก็บไว้ในตัวแปรเพื่อใช้ภายใน scope หนึ่งๆได้ มีประโยชน์มากเมื่อใช้ในการคำนวณสมการ
เช่น หากเราต้องการแทนเลข 2 ด้วยตัวแปร x ทำได้ดังนี้
(let [x 2] x)
;=> 2
ตัวแปร x จะแทนค่าเท่ากับ 2 เมื่อแสดงผลของ x จึงออกมาเท่ากับ 2
และ x จะมีค่าเท่ากับ 2 ใน scope ของ let เท่านั้น ดังตัวอย่าง
(let [x 2] x)
(prn x)
;=> java.lang.RuntimeException: Unable to resolve symbol: x in this context
โปรแกรมฟ้องว่าหา x ไม่เจอ ไม่สามารถใช้ x ได้
อีกตัวอย่างของการใช้ let
(let [a 1 b 2]
(+ a b))
;=> 3
ตัวแปร a จะแทนค่าเท่ากับ 1 ส่วนตัวแปร b จะแทนค่าเท่ากับ 2 หลังจากนั้นนำ a b มาบวกกัน ผลลัพธ์จึงออกมาเป็น 3
ใน Clojure เราสามารถเช็คเงื่อนไขด้วยคำสั่ง if ได้ โดยรับ argument 3 ตัว หาก argument ตัวที่ 1 เป็น true ฟังค์ชันจะ return argument ตัวที่ 2 ออกมาเป็น output
หากเป็น false ฟังค์ชันจะ return argument ตัวที่ 3 ออกมาเป็น output
(if true “yes” “no”)
;=> “yes”(if false “yes” “no”)
;=> “no”
ตัวอย่างแรก ผลลัพท์เป็น yes เพราะรับค่า true
ตัวอย่างถัดไปผลลัพท์เป็น no เพราะรับค่า false
ตัวอย่างโจทย์ จงหาเลขที่รับเข้ามาว่าเป็นเลขคู่หรือเลขคี่
(defn evenOdd? [number]
(if (= (mod number 2) 0) “even” “odd”))
(evenOdd? 2)
;=> “even”(evenOdd? 3)
;=> “odd”
cond คือ คำสั่งที่มีลักษณะคล้ายกับ switch case ในภาษา c
ตัวอย่าง จงหาเลขที่รับเข้ามาว่ามีค่ามากกว่า 100 หรือไม่
(defn test [x]
(cond
(< x 100) “less than”
(> x 100) “greater than”
: else “equal 100”))
(test100 20)
;=> “less than”(test100 150)
;=> “greater than”(test100 100)
;=> “equal 100”
คำสั่ง for จะ loop และสร้างเป็น list ออกมา
เช่น ต้องการหาพื้นที่สี่เหลี่ยมจัตุรัสที่มีความกว้างตั้งแต่ 1 ถึง 10
(for [x (range 1 11)]
(* x x))
;=> (1 4 9 16 25 36 49 64 81 100)
จากตัวอย่าง สร้าง x ใช้ในการวน loop ใน list ทำให้ x มีค่าตั้งแต่ 1 ถึง 11 นำค่า x ที่ได้จาก list นำมาคูณกันเป็นการหาพื้นที่สี่เหลี่ยมจัตุรัส
doseq เป็นคำสั่งวน loop โดยจะไม่ return ค่าออกมา แต่จะ execute คำสั่งภายใน loop เฉยๆ
เช่น ต้องการหากำลังสองของเลขคี่ที่น้อยกว่า 6 ออกทาง command line
(doseq [x (range 6)
:when (odd? x)
:let [y (* x x)] ]
(println [x y]) )test.clj: [1 1]
test.clj: [3 9]
test.clj: [5 25]
จากตัวอย่างใช้ doseq ที่มีตัวแปร x ใช้ในการวน loop ใน list ให้ x มีค่าตั้งแต่ 1 ถึง 6 นำค่า x ที่ได้จาก list ไปเช็คว่าเป็นเลขคี่หรือไม่ ถ้าใช่ให้นำไปยกกำลังสองและเก็บไว้ใน y แล้วแสดงผลออกมา
สรุป
Clojure มีคำสั่งพื้นฐานมากมายให้ใช้ซึ่งโค้ดที่ได้ออกมาสั้นมากๆ ยังมีอีกหลายคำสั่งให้ลองเล่น ลองเข้าไปดูที่ https://clojure.org/api/cheatsheet และความสามารถของมันยังไม่หมดเพียงเท่านี้ ในบทความหน้าเราจะมาสอนคำสั่ง Clojure ในระดับ Advance กัน