Зачем нам funcall в Лиспе? - PullRequest
       64

Зачем нам funcall в Лиспе?

16 голосов
/ 16 марта 2012

Почему мы должны использовать funcall для вызова функций высшего порядка в Common Lisp? Например, почему мы должны использовать:

(defun foo (test-func args)
  (funcall test-func args))

вместо простого:

(defun bar (test-func args)
  (test-func args))

Исходя из процедурного фона, я немного удивлен тем, что языки, к которым я более привык (например, Python, C #), не нуждаются в различении. В частности, по крайней мере на уровне исходного кода компилятор C # преобразует его в нечто вроде func.invoke().

Единственная проблема, которую я вижу, состоит в том, что это означает, что мы больше не можем вызывать глобальную функцию test-func, потому что она будет затенена, но это вряд ли проблема.

Ответы [ 3 ]

19 голосов
/ 16 марта 2012

Строго говоря, funcall не понадобится, но есть некоторые списки (реализации list-2, такие как Common Lisp), которые разделяют пространство имен переменных пространства имен функций . Реализации Списка 1 (например, Схема) не делают этого различия.

Более конкретно, в вашем случае, test-func находится в пространстве имен переменной.

(defun foo (test-func args)
  (funcall test-func args))

Следовательно, вам нужна конструкция, которая фактически ищет объект функции, связанный с этой переменной, в пространстве имен переменных. В Common Lisp эта конструкция имеет вид funcall.

См. Также этот ответ .

15 голосов
/ 16 марта 2012

Большинство Лиспов имеют два пространства имен (функции и переменные).Имя ищется в пространстве имен функции, когда оно появляется как первый элемент в S-выражении, а в противном случае в пространстве имен переменной.Это позволяет вам присваивать имена вашим переменным, не беспокоясь о том, являются ли они теневыми функциями: поэтому вы можете назвать свою переменную list вместо того, чтобы указывать ее как lst.

Однако это означает, что когда вы сохраняетеФункция в переменной, вы не можете вызвать ее как обычно:

(setq list #'+) ; updates list in the variable namespace
(list 1 2 3) => (1 2 3) ; looks up list in the function namespace

Отсюда необходимость funcall и apply:

(funcall list 1 2 3) => 6 ; looks up list in the variable namespace

(Не все Лиспы имеют два пространства имен: Схема является примером Лиспа только с одним пространством имен.)

0 голосов
/ 16 марта 2012

В Common Lisp, между прочим, каждый символ может быть связан с его символ-функцией и символ-значением . При чтении списка Common Lisp по умолчанию интерпретирует:

  • arg1 как функция и, таким образом, получает test-func s symbol-function, который не определен - таким образом, функция bar не работает
  • arg2 как нечто, что должно быть eval ed - таким образом, функция foo извлекает test-func 'symbol-value, которая, в вашем случае, оказывается функцией
...