อาจจะอยู่ในการปิดบัง

กำลังพยายามเขียนฟังก์ชันที่ประกอบขึ้นใน clojure ที่ออกที่ค่าศูนย์แรก (เช่นสิ่งที่คุณทำโดยการผูกมัด Maybes ไว้ด้วยกันใน haskell) ด้วยสิ่งต่อไปนี้:

(defn wrap [f] (fn [x] (if (nil? x) nil (f x))))

(defn maybe [arg & functs] ( (comp (reverse (map wrap functs))) arg))

เพื่อที่ฉันจะได้เช่น

(defn f1 [x] (+ x 1))

(maybe 1 f1 f1 ) => 3

(maybe nil f1 f1) => nil

ซึ่งน่าเสียดายที่ให้สิ่งนี้แก่ฉัน: ClassCastException clojure.lang.PersistentList ไม่สามารถส่งไปยังผู้ใช้ clojure.lang.IFn/อาจจะ (NO_SOURCE_FILE:1)

ใครสามารถให้ความช่วยเหลือในสิ่งที่ฉันทำผิดที่นี่? วิธีสำนวนในการทำเช่นนี้คืออะไร?


person Steve B.    schedule 14.05.2015    source แหล่งที่มา
comment
wrap ทำอย่างนั้น (และ x (f x )) ไม่ทำอะไร?   -  person RedDeckWins    schedule 14.05.2015


คำตอบ (4)


วิธีที่ใช้สำนวนในการทำเช่นนี้คือการใช้ some-> ดูเอกสารประกอบของสิ่งนี้ มาโครเพื่อดูรายละเอียดเพิ่มเติม

อย่าปล่อยให้สิ่งนั้นมาขัดขวางไม่ให้คุณสร้างมันขึ้นมาเองแน่นอน!

person WolfeFan    schedule 14.05.2015
comment
โปรดทราบว่าการใช้งานที่ได้จะแตกต่างออกไปเล็กน้อย มาโคร some-> จะส่งผลลัพธ์ของคุณผ่านแบบฟอร์มโดยปริยายอย่างดี และไม่สามารถเขียนได้ ในขณะที่ฟังก์ชันบางทีต้องการฟังก์ชันจริง แต่สามารถเขียนได้ เช่น. (some->> [1] (map inc)) แต่ (maybe [1] #(map inc %)) - person Dax Fohl; 14.05.2015
comment
@DaxFohl คุณหมายถึงว่ามันไม่สามารถประกอบได้เพราะเป็นมาโครใช่ไหม ตัวอย่างทั้งสองในความคิดเห็นของคุณแตกต่างกันอย่างไร - person muhuk; 15.05.2015
comment
@muhuk ใช่มันไม่สามารถประกอบได้เพราะเป็นมาโคร หากคุณต้องการสร้างรายการฟังก์ชันขณะรันไทม์เพื่อดำเนินการในลักษณะนี้ คุณไม่สามารถทำได้ด้วย some-> ข้อแตกต่างก็คือ (map inc) สั้นกว่ามาก แต่ไม่ใช่นิพจน์ที่จะคอมไพล์นอกมาโคร some-> - person Dax Fohl; 15.05.2015
comment
เข้าใจแล้ว. มันไม่ได้ทำให้ some-> ตัวเองไม่สามารถประกอบได้จริงๆ นอกจากนี้คุณยังสามารถ (def f #(map inc %)) และ (some->> [1] (f)) ได้หากต้องการ - person muhuk; 15.05.2015
comment
@muhuk บอกว่าคุณมี (defn runall [arg & functs] ((comp (reverse functs)) arg)) แค่ maybe โดยไม่มี wrap คุณสามารถเลือกระหว่างรันไทม์ได้ (let [myfunc (if whatever maybe runall)] (myfunc input f1 f2 f3)) ไม่สามารถทำเช่นนี้กับ some-> นั่นคือสิ่งที่ผู้คนหมายถึงเมื่อพวกเขาพูดว่ามาโครไม่สามารถประกอบได้ - person Dax Fohl; 15.05.2015

comp คาดหวังให้แต่ละฟังก์ชันเป็นอาร์กิวเมนต์เดี่ยว แต่คุณกำลังส่งรายการฟังก์ชันเป็นอาร์กิวเมนต์เดียว หากต้องการแก้ไขปัญหานี้ ให้ใช้ apply

(defn maybe [arg & functs] ( (apply comp (reverse (map wrap functs))) arg))
person Dax Fohl    schedule 14.05.2015

มีเนมสเปซ clojure.algo.monads พร้อมด้วย maybe-m monad เสมอ:

(with-monad maybe-m
  (defn adder [x]
    (let [f (fn [x] (+ x 1))]
      (domonad
        [a x
         b (f a)
         c (f b)]
       c))))

(adder 1)
=> 3 

(adder nil)
=> nil

เป็นที่ยอมรับว่ามันอาจจะเกินความต้องการของคุณไปสักหน่อย

person Mark Fisher    schedule 15.05.2015

ฉันรู้ว่าสิ่งนี้ได้รับคำตอบแล้ว และฉันได้ตั้งคำถามไว้แล้ว แต่คิดว่าฉันจะเพิ่มสิ่งต่อไปนี้เนื่องจากฉันได้เล่นกับมันโดยใช้ monads อีกครั้ง และดูเหมือนเป็นคำถามที่ดีที่จะโพสต์ต่อต้าน

เมื่ออ่าน บทความนี้เกี่ยวกับ threading monads ฉันสามารถมาได้ ต่อไปนี้โดยขยายแมโคร m-> ที่กำหนดไว้ในบทความเพื่อสร้างเธรดที่อาจจะเป็น monad เพื่อการใช้งานที่ง่ายขึ้น TBH มันไม่ได้ง่ายไปกว่านี้อีกแล้วเพียงแค่ใช้ some-> แต่นี่เป็นเพียงเพื่อความอยากรู้ส่วนตัว

ตกลง เพื่อเริ่มต้น มีโค้ดหม้อไอน้ำที่ต้องกำหนด ที่นี่ (ในกรณีที่บทความหายไป) คือคำจำกัดความ monad แบบเธรดของ Giles:

(defn bind-monadic-expr-into-form [insert form]
  (list 'm-bind insert
        (if (seq? form)
          `(fn [bound#] (~(first form) bound# ~@(rest form)))
          `(fn [bound#] (~form bound#)))))

(defmacro m->
  ([m x]
   `(with-monad ~m ~x))
  ([m x form]
   `(with-monad ~m
                ~(bind-monadic-expr-into-form x form)))
  ([m x form & more]
   `(m-> ~m (m-> ~m ~x ~form) ~@more)))

ขณะนี้คุณสามารถกำหนดมาโครแบบเธรดได้

(defmacro maybe->
  ([x] `(m-> ~maybe-m ~x))
  ([x form] `(m-> ~maybe-m ~x ~form))
  ([x form & more] `(maybe-> (maybe-> ~x ~form) ~@more)))

และใช้มันเหมือน:

(maybe-> 1 inc)
=> 2

(maybe-> [1 2] (#(map inc %)))
=> (2 3)

(defn f1 [x] (+ 1 x))
(maybe-> 1 f1 f1)
=> 3

(maybe-> 1 f1 ((constantly nil)) f1)
=> nil

(maybe-> {:a 1 :b 2} :c inc)
=> nil

ไม่มีประโยชน์เลยในการใช้สิ่งนี้กับ some-> ในบริบทนี้ แต่ m-> monad เพิ่มความสามารถที่น่าสนใจในการสร้างแมโคร fail-> เช่นเดียวกับในบทความที่ฉันเชื่อมโยง ซึ่งให้ผลตอบแทนมากกว่า "ศูนย์" โดยให้ คุณสามารถแยกแยะสาเหตุของความล้มเหลวได้

person Mark Fisher    schedule 18.05.2015