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 อีกในครั้งต่อๆ ไป

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s