Monthly Archives: June 2018

ใช้ every-pred แทน and และใช้ some-fn แทน or

ผมไม่ค่อยได้มีโอกาสใช้สองฟังก์ชันนี้บ่อยครั้งนัก วันนี้นึกขึ้นมาได้ว่ามันใช้สำหรับ compose predicate function เทียบได้กับ and และ or เลย

(def products 
  [{:id 1 :stocked true :price 85}
   {:id 2 :stocked true :price 200}
   {:id 3 :stocked false :price 50}
   {:id 4 :stocked false :price 150}])

(defn cheap? [p] (< p 100))

โค้ดสองบรรทัดต่อไปนี้ให้ผลลัพธ์เดียวกัน

(filter #(and (:stocked %) (cheap? (:price %))) products)
(filter (every-pred :stocked (comp cheap? :price)) products)

และโค้ดสองบรรทัดต่อไปนี้ให้ผลลัพธ์เดียวกัน

(filter #(or (:stocked %) (cheap? (:price %))) products)
(filter (some-fn :stocked (comp cheap? :price)) products)

พอสรุปได้แบบนี้แล้ว น่าจะได้หยิบมันมาใช้บ่อยขึ้น

Advertisements

cond กับ expensive get function

สมมติว่าฟังก์ชั่น fn1 เป็นฟังก์ชันที่คืนเป็นค่าใดๆจาก collection หรือคืนค่าเป็น nil แต่ฟังก์ชัน fn1 นี้ต้องใช้การประมวลผลเยอะ ผมไม่อยากรันมันหลายครั้งถ้าไม่จำเป็น พอมันต้องไปอยู่เป็นหนึ่งในเงื่อนไขของ cond ผมจึงไม่อยากทำแบบนี้เพราะผมต้องรันมัน 2 ครั้ง

(cond
  criteria1 return1
  criteria2 return2
  criteria1 return3
  (fn1) (fn1)
  :else some-other-thing)

ผมไม่อยาก let มันเอาไว้ก่อนเพราะเงื่อนไขนี้อาจจะไม่ต้องถูกคำนวณถ้าเงื่อนไขก่อนหน้าสำเร็จไปก่อนแล้ว เช่น ในกรณีนี้ criteria1, criteria2 หรือ criteria3 อาจจะเป็นจริงทำให้ fn1 ไม่จำเป็นต้องถูกรัน

(let [x (fn1)]
  (cond
    criteria1 return1
    criteria2 return2
    criteria3 return3
    x x
    :else some-other-thing))

ผมอยากได้อะไรคล้ายๆ กับ if-let หรือ when-let ที่ผมสามารถนำผลลัพธ์ที่ใช้ตรวจสอบเงื่อนไขไปใช้เป็นค่า return ได้ แต่ cond ไม่มีสิ่งนี้ให้ผมใช้

(cond
  criteria1 return1
  criteria2 return2
  criteria3 return3
  (let [x (fn1)] x) x
  :else some-other-thing)

ผมเจอปัญหานี้บ่อย คิดวิธีแก้ไม่ออกซักที แต่วันนี้ผมคิดออกแล้ว! เอา delay มาช่วยไง

(let [x (delay (fn1))]
  (cond
    criteria1 return1
    criteria2 return2
    criteria3 return3
    @x @x
    :else some-other-thing))

delay จะทำการห่อ form ที่อยู่ข้างใน ไม่ทำการ evaluate มันจนกว่าตัว delay จะถูก dereference ด้วย @ หรือ deref จากนั้นมันจะทำการเก็บผลลัพธ์ไว้ คืนค่าเดิมทุกครั้งเมื่อถูก dereference อีกในครั้งต่อๆ ไป