Basic Clojure Command

Arm Pacino
Technologies For Everyone
3 min readMar 28, 2017

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 กัน

--

--