這是abs完全可能!你快到了。你碰到Common Lisp的雙重命名空間,這可能需要很多習慣。我希望我能說一兩句讓Common Lisp的兩個命名空間不那麼困惑。
你的代碼幾乎是正確的。你寫道:
(defun foo (fn seq)
(mapcar #'fn seq))
但是,那是在做什麼?那麼,#'是速記。我會爲你擴展它。
(defun foo (fn seq)
(mapcar (function fn) seq))
所以,#「符號是簡寫(函數符號)。在Common Lisp中 - 正如你所知道的那樣 - 符號可以綁定到一個函數和一個變量;這些是Lispers談論得非常多的兩個命名空間:函數名稱空間和變量名稱空間。
現在,函數特殊形式所做的是獲取綁定到符號的函數,或者,如果您願意,函數名稱空間中符號具有的值。
現在,在REPL上,你寫的東西顯然是你想要的。
(mapcar #'car sequence)
請問車功能映射到列表的順序。和汽車符號沒有可變綁定,只有一個函數綁定,這就是爲什麼你需要使用(函數...)(或其簡寫,#')來獲得實際功能。
你富功能不起作用,因爲你把它作爲一個參數的函數被綁定到一個符號作爲變量。試試這個:
(let ((fn #'sqrt))
(mapcar #'fn '(4 9 16 25)))
你可能期望所有這些數字平方根的名單,但沒有奏效。這是因爲您使用讓將平方根函數綁定爲fn作爲變量。現在,試試這個代碼:
(let ((fn #'sqrt))
(mapcar fn '(4 9 16 25)))
令人愉快!這將平方根函數與作爲變量的符號綁定在一起。
所以,讓我們去修改你的富功能:
(defun foo (fn seq)
(mapcar fn seq))
這將的工作,因爲FN是可變的。讓我們測試一下,只是爲了確保:
;; This will not work
(foo sqrt '(4 9 16 25))
;; This will work
(foo #'sqrt '(4 9 16 25))
第一個沒有工作,因爲平方根函數被綁定到函數命名空間開方。因此,在第二個中,我們從符號中抓取了函數,並將其傳遞給foo,並將其作爲變量綁定到符號fn。
好了,所以如果你想要的功能綁定到函數命名空間的象徵?那麼,對於初學者來說,defun這樣做是永久性的。如果你想要它是暫時的,就像讓綁定,使用flet。 Flet在我看來是愚蠢的,因爲它不能像let一樣工作。但是,我會舉一個例子,讓你可以看到。
(flet ((fn (x) (sqrt x)))
(mapcar fn '(4 9 16 25)))
將無法正常工作,因爲FLET沒有的功能綁定到變量命名空間中的符號,但在功能的命名空間。
(flet ((fn (x) (sqrt x)))
(mapcar #'fn '(4 9 16 25)))
這將做你所期望的,因爲FLET約束,且功能的函數命名空間的符號FN。而且,只是驅動函數命名空間的家的想法:
(flet ((fn (x) (sqrt x)))
(fn 16))
將返回4.
+1哇,那是相當的一些答案。很詳細。 :-) – 2012-01-08 04:44:23