Функция составления в On Lisp Пола Грэма (а также в Ansi Common Lisp) - PullRequest
1 голос
/ 14 марта 2020

В книге Пола Грэма, на Лиспе, стр. 66, у нас есть эта функция:

(defun compose (&rest fns)
  (if fns
      (let ((fn1 (car (last fns)))
            (fns (butlast fns)))
        #'(lambda (&rest args)
            (reduce #'funcall fns
                    :from-end t
                    :initial-value (apply fn1 args))))
      #'identity))

[эта функция написана так, как в книге Пола Грэма, Ansi Common Lisp, стр. 110]:

(defun compose (&rest fns)
  (destructuring-bind (fn1 . rest) (reverse fns)
     (lambda (&rest args)
       (reduce #'(lambda (v f) (funcall f v))
               rest
               :initial-value (apply fn1 args)))))

, что дает, например:

CL-USER> (funcall (compose #'1+ #'find-if) #'oddp '(2 3 4))
4

Я знаю, что вопросы об этой функции уже задавались и что было дано много ответов: (составить) в Common Lisp
Составьте пример в ANSI Common Lisp Пола Грэма

Но всегда есть одна вещь, которая мне не ясна. Я знаю, что:

fn1 <# <FUNCTION FIND-IF>
fns <(# <FUNCTION 1+>)>  
args <(#<FUNCTION ODDP> (2 3 4))> 

Тем не менее, я не понимаю, как работает инструкция:

(apply fn1 args)

Я думал, что при тестировании по отдельности, заменяя fn1 на #'find-if, и args с (#'oddp (2 3 4)):

(apply #'find-if #'oddp '(2 3 4))  
or
(apply #'find-if (#'oddp (2 3 4)))  

это будет работать, но это не так:

CL-USER> (apply #'find-if #'oddp '(2 3 4))
; Evaluation aborted on #<UNKNOWN-KEYWORD-ARGUMENT {10036BBD03}>.

CL-USER> (apply #'find-if (#'oddp (2 3 4)))
; Evaluation aborted on #<SB-INT:COMPILED-PROGRAM-ERROR {1003DE6413}>.

CL-USER> (apply #'find-if '(#'oddp (2 3 4)))
; Evaluation aborted on #<TYPE-ERROR expected-type: (OR FUNCTION SYMBOL) datum: #'ODDP>.

Может кто-нибудь объяснить мне, как работает эта инструкция? Заранее благодарим за вашу снисходительность и ваши ответы.

1 Ответ

4 голосов
/ 14 марта 2020

Допустим, вы хотите создать список из трех элементов: функциональный объект и два числа. Использовать

(list #'+ 1 2)

Не использовать:

(#'+ 1 2)     ; that's not valid Common Lisp code. The
              ;  first element of a Lisp form can't be a function object.
              ;  It's violating the basic evaluation rules
              ;  of Common Lisp.

'(#'+ 1 2)    ; This does not evaluate the list. Quoting makes it
              ;  a constant literal list. The elements of the list
              ;  won't be evaluated.
              ; Thus the first item is not a function object,
              ; but the list (function +)

Определение:

Форма Lisp : допустимый код, подлежащий оценке

...