> 1 <

Автор Сообщение

d_s__

Members


Статус

10 сообщений

Где: Russia
Род занятий:
Возраст:

#7842   2018-02-04 20:39 GMT+3 часа(ов)      
Непонятна роль funcall при вызове функции, порожденной другой функцией в CL.

1)
* (defun foo (x) (+ x 10))
FOO
Сначала определяется символ FOO как символ, указывающий на объект-функцию, которая к к аргументу прибавляет 10.

2)
* (foo 2)
12
Сначала вычисляется аргумент 2 - так как он самовычисляемый - то получается 2, затем по символу функции вычисляется объект-функция и происходит вызов объекта-функции с аргументом 2. Результат: 12

3)
* (funcall 'foo 2)
12
Можно тот же результат получить через funcall, передав в него СИМВОЛ, указывающий на функцию

4)
* (defun voo () (lambda (x) (+ x 10)))
VOO
* (voo)
#<FUNCTION (LAMBDA (X) :IN VOO) {AC6C39D}>
Создали функцию которая возвращает объект-функцию (а не символ, указывающий на функцию)

5)
По идее далее должно работать, но не работает
*((VOO) 2) - ошибка!
По идее, сначала должна вычислиться 2, потом (voo), которая возвращает объект-функцию - и данных уже достаточно для вызова этой функции с аргументом 2

6)
Но работает
*(funcall (voo) 4)
14
При это в данном случае мы передаем funcall НЕ СИМВОЛ, а саму объект-функцию.

Что-то у меня никак не бьется в голове пункты 3) и 6)

Про то, что в CL два пространства имен - в курсе. Но не могу понять как из этого следует необходимость использования funcall - ведь мы объект-функцию подаем уже "на блюдечке с голубой каемочкой".
В каком месте я "туплю"? c Scheme все понятнее - там ((VOO) 2) работает нормально.
На каком-то этапе вычислений не понятно где лежит объект-функция?

antares0

Members


Статус

185 сообщений

Где: Russia
Род занятий:
Возраст:

#7843   2018-02-05 06:52 GMT+3 часа(ов)      
В время компиляции (foo) еще не вызвана, окуружение для ее вызова еще не создано, ее результат существует лишь в голове програмиста => компилятор не сможет сделать быстрый маш. код для этого. В процессе стандартизации эту возможность зарезали, разделив на flet времени компиляции и funcall времени исполнения.
Funcall - явное заявление что функцию мы будем искать в время исполнения, а пока компиляция давай посмотрим как сооптимизировать хотя бы аргументы. Ну и традиция лиспа требует что бы список обрабатвался согласно его первому символу

antares0

Members


Статус

185 сообщений

Где: Russia
Род занятий:
Возраст:

#7844   2018-02-05 06:58 GMT+3 часа(ов)      
Схемы разрешат это потиворечие либо уходом от компиляции с потерей производительности. либо уходом от "горячего" изменяемого образа в С-шную детерминированость которая замораживает поведение всей програмы.

skelter

Members


Статус

56 сообщений

Где: ---
Род занятий:
Возраст:

#7845   2018-02-05 08:12 GMT+3 часа(ов)      
Цитата
Сначала вычисляется аргумент 2 - так как он самовычисляемый - то получается 2, затем по символу функции вычисляется объект-функция и происходит вызов объекта-функции с аргументом 2.


Про функцию неточно написано, она не вычисляется (в смысле вычисления выражения).

На первом месте выражения обязательно стоит символ. (На самом деле я вру, там может быть лямбда-выражение, но забудем про эту возможность.) Первым делом лисп смотрит, что это за символ. Если символ является не является именем специальной формы или макроса, то лисп считает, что это имя функции, и находит функцию с этим именем.

Уже после того, как лисп разберётся с первым элементом списка - именем функции, он вычисляет аргументы и применяет функцию к аргументам.

То есть лиспу не нужна в голове функция. Ему нужно имя функции. И отдельное пространство имён функций как раз означает, что отношение «символ является именем функции» ортогонально использованию символов как переменных, меток и т. п. В частности, «символ является именем функции» и «символ является именем переменной, значением которой является функция» - существенно разные вещи. Функцию по имени ищет специальный оператор function, который сокращается до #' . Например, (function foo) и #'foo - это «функция по имени foo» (сама функция, а не имя).

Поэтому ((voo) 2) не работает: на первом месте списка стоит не имя функции, а выражение. Синтаксическая ошибка.

Это всё касается синтаксиса лиспа как конкретного языка программирования, то есть лиспоспецифические (даже CL-специфические) вопросы.

funcall к синтаксису отношения не имеет. Это в первую очередь оператор применения функции к аргументам. Применение функции — тоже операция. В математике её называют «отображение вычисления», но стандартного обозначения у неё нет, а в хаскеле есть - доллар (помимо пробела). В CL это обычная функция, funcall. Поэтому (funcall (voo) 2) прекрасно работает. Когда аргументы funcall-а вычисляются, получается функция и число, и funcall применяет функцию к числу.

Если у нас на руках есть функция (скажем, результат вычисления выражения), и мы желаем её к чему-то применить, синтаксис не даёт этой возможности, поэтому приходится явно использовать funcall: (funcall (voo) 4).

С этой точки зрения непонятно, почему работает (funcall 'foo 2), ведь его первый аргумент - символ, а не функция. Дело в том, что иногда вместо объекта конкретного типа разрешается использовать «аналогичный» объект другого типа. В лиспе это называется designator: один объект «обозначает собой» другой. Например, часто можно использовать строки вместо имён файлов или символы вместо строк (обычно так делают при определении пакета). Так и funcall, если посмотреть документацию, принимает не функцию, а, более общо, function designator, то есть или функцию, или символ - имя глобальной функции. То есть (funcall 'foo 2) - это (почти) то же, что (funcall #'foo 2). Так же ведут себя некоторые другие стандартные функции: например, mapcar.

d_s__

Members


Статус

10 сообщений

Где: Russia
Род занятий:
Возраст:

#7846   2018-02-05 11:51 GMT+3 часа(ов)      
Спасибо - стало понятнее.
Все это дает очень интересный эффект:

* (defun foo (x) (+ x 10))

FOO
* (defvar foo (lambda (x) (+ x 100)))

FOO
* (foo 4)

14
* (funcall foo 4)

104
* (funcall 'foo 4)

14
* (funcall (function foo) 4)

14
* foo

#<FUNCTION (LAMBDA (X)) {AC256FD}>
* (function foo)

#<FUNCTION FOO>
*
> 1 <


Онлайн :

0 пользователь(ей), 28 гость(ей) :




Реклама на сайте: