ฟังก์ชันชวเลขที่ไม่ระบุชื่อ


85

มีบางอย่างที่ฉันไม่เข้าใจเกี่ยวกับฟังก์ชันที่ไม่ระบุชื่อโดยใช้สัญกรณ์สั้น ๆ # (.. )

ผลงานดังต่อไปนี้:

REPL>  ((fn [s] s) "Eh")
"Eh"

แต่สิ่งนี้ไม่:

REPL>  (#(%) "Eh")

ใช้งานได้:

REPL> (#(str %) "Eh")
"Eh"

สิ่งที่ฉันไม่เข้าใจคือทำไม(# (%) "เอ๊ะ")ไม่ทำงานและในขณะเดียวกันฉันก็ไม่จำเป็นต้องใช้str in ((fn [s] s) "เอ๊ะ")

ทั้งสองเป็นฟังก์ชันที่ไม่ระบุตัวตนและทั้งคู่ใช้พารามิเตอร์เดียวที่นี่ เหตุใดสัญกรณ์ชวเลขจึงจำเป็นต้องมีฟังก์ชันในขณะที่สัญกรณ์อื่นไม่มี

คำตอบ:


126
#(...)

เป็นชวเลขสำหรับ

(fn [arg1 arg2 ...] (...))

(โดยที่จำนวน argN ขึ้นอยู่กับจำนวน% N ที่คุณมีในร่างกาย) ดังนั้นเมื่อคุณเขียน:

#(%)

แปลเป็น:

(fn [arg1] (arg1))

สังเกตว่าสิ่งนี้แตกต่างจากฟังก์ชัน anonymous แรกของคุณซึ่งเหมือนกับ:

(fn [arg1] arg1)

เวอร์ชันของคุณส่งคืนค่า arg1 เป็นค่าเวอร์ชันที่มาจากการขยายชวเลขพยายามเรียกมันว่าเป็นฟังก์ชัน คุณได้รับข้อผิดพลาดเนื่องจากสตริงไม่ใช่ฟังก์ชันที่ถูกต้อง

เนื่องจากชวเลขให้ชุดวงเล็บรอบตัวจึงสามารถใช้เพื่อเรียกใช้ฟังก์ชันเดี่ยวหรือรูปแบบพิเศษเท่านั้น


65

เนื่องจากคำตอบอื่น ๆ ได้ชี้ให้เห็นอย่างชัดเจนแล้วสิ่งที่#(%)คุณโพสต์จะขยายไปสู่สิ่งที่ต้องการ(fn [arg1] (arg1))ซึ่งไม่เหมือนกับ(fn [arg1] arg1)เลย

@John Flatness ชี้ให้เห็นว่าคุณสามารถใช้ได้identityแต่ถ้าคุณกำลังมองหาวิธีเขียนidentityโดยใช้#(...)มาโครการจัดส่งคุณสามารถทำได้ดังนี้:

#(-> %)

ด้วยการรวม#(...)มาโครการจัดส่งเข้ากับมาโคร->เธรดมันจะขยายเป็นบางอย่างเช่น(fn [arg1] (-> arg1))ซึ่งขยายอีกครั้งเป็น(fn [arg1] arg1)ซึ่งเป็นเพียงที่คุณต้องการ ฉันยังพบว่าคำสั่งผสม->และ#(...)มาโครมีประโยชน์สำหรับการเขียนฟังก์ชันง่ายๆที่ส่งคืนเวกเตอร์เช่น:

#(-> [%2 %1])

21

เมื่อคุณใช้#(...)คุณสามารถจินตนาการได้ว่าคุณกำลังเขียนแทน(fn [args] (...))ซึ่งรวมถึงวงเล็บที่คุณเริ่มต้นหลังเงินปอนด์ด้วย

ดังนั้นตัวอย่างที่ไม่ทำงานของคุณจะแปลงเป็น:

((fn [s] (s)) "Eh")

ซึ่งเห็นได้ชัดว่าใช้ไม่ได้เพราะคุณพยายามเรียกสตริงว่า "เอ๊ะ" ตัวอย่างเช่นคุณกับstrงานเพราะตอนนี้ฟังก์ชั่นของคุณแทน(str s) จะเป็นอะนาล็อกที่ใกล้เคียงกับตัวอย่างแรกของคุณมากขึ้นเนื่องจากจะไม่บังคับให้ str(s)(identity s)

มันสมเหตุสมผลถ้าคุณคิดเกี่ยวกับเรื่องนี้เนื่องจากนอกเหนือจากตัวอย่างที่เรียบง่ายนี้แล้วทุกฟังก์ชันที่ไม่ระบุตัวตนจะเรียกอะไรบางอย่างดังนั้นจึงเป็นเรื่องโง่เล็กน้อยที่ต้องใช้ชุด parens ที่ซ้อนกันอีกชุดหนึ่งเพื่อโทรออกจริงๆ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.