2014-07-01 26 views
1

爲什麼沒有語法糖的funcall?我們需要很多。用(&#do-something arg0 arg1 arg2)而不是(funcall do-something arg0 arg1 arg2)爲什麼不添加類似Ruby的&:方法符號?語言中是否有某些東西?語音糖爲funcall?

回答

7

沒有什麼像內置的語言;您可以輕鬆地將該功能分配給其他名稱,然後使用該名稱。例如,如果你想使用&,您可以:

CL-USER> (setf (symbol-function '&) (symbol-function 'funcall)) 
#<FUNCTION FUNCALL> 
CL-USER> (&'list 1 2 3) 
(1 2 3) 
CL-USER> (&'cons 'x 'y) 
(X . Y) 

(有大約不同的方式來做到這一點一線上堆棧溢出最近的問題:How to stop evaluating lisp form when passed as function parameter?

不會吧寫好像(&#do-something arg0 arg1 arg2)而不是(funcall do-something arg0 arg1 arg2)

可能不是。 Common Lisp是一種傾向於函數和宏的表達式名稱的語言。 funcall這個名字是可以識別的,它清楚地表明有一個間接的函數調用正在發生。我們爲什麼要模糊這一點?很顯然,大多數人認爲funcall在「足夠短的寫作」和「足夠長的描述性」之間具有適當的平衡。

爲什麼沒有語法糖funcall?

你可能會在Common Lisp中調用宏「語法糖」,但這裏不需要它。 Funcall是一個函數,而不是一個特殊的形式或宏,所以它真的很容易用別名將其別名,如上所示。事實上,大多數人這樣做應該說一些關於它是多麼令人滿意。

4

如果你傾向於魔法:

(defun black-magic (stream sub-char numarg) 
    (declare (ignore sub-char numarg)) 
    `(funcall ,@(read stream))) 

(set-dispatch-macro-character 
    #\# #\! #'black-magic) 

粗糙例如:

CL-USER> (defun foo (fn x y z) 
      #!(fn x y z)) 
FOO 
CL-USER> (foo #'* 1 2 3) 
6 
CL-USER> (foo #'+ 1 1 1) 
3 

(這是更好不過使用apply ...但讓事情變得簡單,使用它甚至更好沒有這種)

我們任何人都可以通過讀者宏定義類似的東西,但我認爲它不是如果你期望有人會閱讀你的代碼somtime,那麼做這樣的事情是一個非常好的主意。

其實這種閱讀器宏是你要求的語法糖。你現在拒絕你自己的想法嗎?每次當你使用非常規的語法糖,你可能會讓你未來的代碼閱讀器變得更糟。

+0

這是這種宏的一個很好的例子,儘管它實際上並不保存任何類型的輸入,而不是一個字符的函數名。例如,'#!(list 1 2 3)'不比'(!'list 1 2 3)'短,並且對於'#!(f x y)'與'(!f x y)'相似。 –

+0

@Joshua,說實話,我沒有看到引入這種語法糖的理由,我總是會使用更長和標準的'(funcall fxy)',我發佈這個選項只是作爲這種事情的一個例子是可能的。 – Mark

5

沒有語法funcall,因爲我們不需要它很多(或者,定義「我們」)。我的意思是,在一個Lisp-2中,比如Common Lisp,這是一個權衡,除非你正在做一些沉重的lambda演算,你會習慣它。

如果你真的想用一個更succint語法,您可以定義一個dispatch macro character

(set-dispatch-macro-character 
#\# #\& 
#'(lambda (stream subchar arg) 
    (let ((args-var (gensym))) 
     `(lambda (&rest ,args-var) 
      (declare (dynamic-extent ,args-var)) 
      (apply ,(read stream t nil t) ,args-var))))) 

(let ((my-function #'max)) 
    (#&my-function 1 3 2)) 

檢查你的編譯器將優化lambda formsdynamic-extent&rest參數傳遞給apply

我建議不要將單個字符&定義爲macro character,因爲它是constituent character,主要用於符號&optional, &rest, &key, &allow-other-keys, &aux, &whole, &body and &environment

+0

美麗!我想過lambda包裝,但決定放在事情之前的'funcall'。 +1 – Mark

+0

您的選項'#!'背後的整個表單也很聰明,它不依賴於優化lambda表單(和'apply'),通過自動避免一次調用/間接尋址。 – acelent

+1

把'&'定義爲一個函數沒有問題,但是它的鍵入量是相同的:'(&my-function 1 3 2)',並且也適用於符號:'(&'list 1 2 3) '。相同數量的輸入,沒有適用的開銷,也沒有調度宏字符的複雜性。 –