2012-01-08 3 views
8

Я просто изучаю ANSI Common Lisp (используя clisp на машине Win32), и мне было интересно, может ли mapcar использовать функцию, переданную как формальный аргумент? Пожалуйста, смотрите следующее:Программирование более высокого порядка с Lisp: передача функции mapcar?

(defun foo (fn seq) 
    (mapcar #'fn seq)) 

Это, на мой взгляд, обеспечить более высокий уровень гибкости, чем:

(defun mult (i) 
    (* i 2)) 

(defun foo() 
    (mapcar #'mult '(1 2 3))) 

ответ

3

Конечно, вы можете сделать это:

(defun foo (fn) 
    (mapcar fn '(1 2 3))) 

Примеры:

(foo #'(lambda (x) (* x 2))) 
(foo #'1+) 
(foo #'sqrt) 
(foo #'(lambda (x) (1+ (* x 3)))) 
28

Это abs возможно! Ты почти там. Вы просто столкнулись с двойными пространствами имен Common Lisp, и это может занять много времени. Надеюсь, я смогу сказать кое-что, чтобы сделать Common namespaces Common Lisp немного менее запутанным.

Ваш код почти правильный. Вы писали:

(defun foo (fn seq) 
    (mapcar #'fn seq)) 

Но что это за попытка? Хорошо, # ' является сокращением. Я расширю его для вас.

(defun foo (fn seq) 
    (mapcar (function fn) seq)) 

Так, символ # 'представляет собой сокращенную (символ функции). В Common Lisp - как вы, кажется, знаете - символы могут быть привязаны к функции и переменной; это два пространства имен, о которых так много говорит Лисперс: пространство имен функций и пространство имен переменных.

Теперь функция особой формы - это функция, привязанная к символу или, если хотите, значение, которое имеет символ в пространстве имен функций.

Теперь, на REPL, то, что вы написали, было бы очевидно, что вы хотите.

(mapcar #'car sequence) 

карта Будет ли автомобиль функцию последовательности списков. И символ не имеет привязки к переменной, только привязка к функции, поэтому вам нужно использовать (функция ...) (или его стенограмма, # '), чтобы получить фактическую функцию.

Вашей Foo функция не работает, так как функция передается в качестве аргумента в настоящее время связана с символом в качестве переменной. Попробуйте следующее:

(let ((fn #'sqrt)) 
    (mapcar #'fn '(4 9 16 25))) 

Возможно, вы ожидали список квадратных квадратов этих чисел, но это не сработало. Это потому, что вы использовали let, чтобы привязать функцию квадратного корня к fn как переменную. Теперь попробуйте этот код:

(let ((fn #'sqrt)) 
    (mapcar fn '(4 9 16 25))) 

Восхитительный!Это связывает функцию квадратного корня с символом fn в качестве переменной.

Итак, давайте пересмотреть ваш Foo функции:

(defun foo (fn seq) 
    (mapcar fn seq)) 

Это будет работа, потому что п является переменной. Давайте проверим это, просто чтобы убедиться:

;; This will not work 
(foo sqrt '(4 9 16 25)) 
;; This will work 
(foo #'sqrt '(4 9 16 25)) 

Первый не работает, так как квадратный корень связан с SQRT в функциональном пространстве имен. Итак, во втором мы взяли функцию из символа и передали ее в foo, которая привязала ее к символу fn как переменную.


Хорошо, а что, если вы хотите связать функцию с символом в пространстве имен функций? Ну, для начала, defun делает это, надолго. Если вы хотите, чтобы он был временным, например, , позвоните, используйте flet. Flet, на мой взгляд, глупый, потому что он не работает точно так же, как пусть делает. Но я приведу пример, чтобы вы могли видеть.

(flet ((fn (x) (sqrt x))) 
    (mapcar fn '(4 9 16 25))) 

не будет работать, потому что FLET не связывает функцию символа в переменном пространстве имен, но в функциональном пространстве имен.

(flet ((fn (x) (sqrt x))) 
    (mapcar #'fn '(4 9 16 25))) 

Это будет делать то, что вы ожидаете, потому что FLET связаны эту функцию с символом п в функциональном пространстве имен. И, чтобы поездить на идею функции пространства имен дома:

(flet ((fn (x) (sqrt x))) 
    (fn 16)) 

Вернется 4.

+0

+1 Ого, это довольно какой-то ответ. Очень подробно. :-) –

Смежные вопросы