Поиск…


Синтаксис

  • (имя функции); извлекает объект функции этого имени
  • #'название ; синтаксический сахар для (имя функции)
  • (символ-функция); возвращает функцию, связанную с символом
  • (функция funcall args ...); функция вызова с помощью args
  • (применить функцию arglist); функция вызова с аргументами, указанными в списке
  • (примените функцию arg1 arg2 ... argn arglist); вызов функции с аргументами, заданными arg1, arg2, ..., argn, а остальные в списке arglist

параметры

параметр подробности
название некоторый (неоцененный) символ, который называет функцию
условное обозначение символ
функция функцию, которая должна называться
арг ... ноль или более аргументов ( не список аргументов)
список аргументов список, содержащий аргументы, передаваемые функции
arg1, arg2, ..., argn каждый из них представляет собой один аргумент, который должен быть передан функции

замечания

Говоря о Lisp-подобных языках, существует общее различие между тем, что известно как Lisp-1 и Lisp-2. В Lisp-1 символы имеют только значение, и если символ относится к функции, то значением этого символа будет эта функция. В Lisp-2 символы могут иметь отдельные связанные значения и функции, поэтому требуется специальная форма для ссылки на функцию, хранящуюся в символе, а не на значение.

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

Определение анонимных функций

Функции в Common Lisp являются значениями первого класса . Анонимную функцию можно создать с помощью lambda . Например, здесь есть функция из 3 аргументов, которые мы затем вызываем с помощью funcall

CL-USER> (lambda (a b c) (+ a (* b c)))
#<FUNCTION (LAMBDA (A B C)) {10034F484B}>
CL-USER> (defvar *foo* (lambda (a b c) (+ a (* b c))))
*FOO*
CL-USER> (funcall *foo* 1 2 3)
7

Анонимные функции также могут использоваться напрямую. Common Lisp предоставляет синтаксис для него.

((lambda (a b c) (+ a (* b c)))    ; the lambda expression as the first
                                   ; element in a form
  1 2 3)                           ; followed by the arguments

Анонимные функции также могут храниться как глобальные функции:

(let ((a-function (lambda (a b c) (+ a (* b c)))))      ; our anonymous function
  (setf (symbol-function 'some-function) a-function))   ; storing it

(some-function 1 2 3)                                   ; calling it with the name

Цитированные лямбда-выражения не являются функциями

Обратите внимание, что цитируемые лямбда-выражения не являются функциями в Common Lisp. Это не работает:

(funcall '(lambda (x) x)
         42)

Чтобы преобразовать цитированное выражение лямбда в функцию, используйте coerce , eval или funcall :

CL-USER > (coerce '(lambda (x) x) 'function)
#<anonymous interpreted function 4060000A7C>

CL-USER > (eval '(lambda (x) x))
#<anonymous interpreted function 4060000B9C>

CL-USER > (compile nil '(lambda (x) x))
#<Function 17 4060000CCC>

Ссылаясь на существующие функции

Любой символ в Common Lisp имеет слот для переменной, подлежащей привязке, и отдельный слот для связанной функции.

Обратите внимание, что именование в этом примере только для иллюстрации. Глобальные переменные не должны называться foo , но *foo* . Последняя нотация - это соглашение, дающее понять, что переменная является специальной переменной, использующей динамическое связывание .

CL-USER> (boundp 'foo) ;is FOO defined as a variable?
NIL
CL-USER> (defvar foo 7)
FOO
CL-USER> (boundp 'foo)
T
CL-USER> foo
7
CL-USER> (symbol-value 'foo)
7
CL-USER> (fboundp 'foo) ;is FOO defined as a function?
NIL
CL-USER> (defun foo (x y) (+ (* x x) (* y y)))
FOO
CL-USER> (fboundp 'foo)
T
CL-USER> foo
7
CL-USER> (symbol-function 'foo)
#<FUNCTION FOO>
CL-USER> (function foo)
#<FUNCTION FOO>
CL-USER> (equalp (quote #'foo) (quote (function foo)))
T
CL-USER> (eq (symbol-function 'foo) #'foo)
T
CL-USER> (foo 4 3)
25
CL-USER> (funcall foo 4 3)
;get an error: 7 is not a function
CL-USER> (funcall #'foo 4 3)
25
CL-USER> (defvar bar #'foo)
BAR
CL-USER> bar
#<FUNCTION FOO>
CL-USER> (funcall bar 4 3)
25
CL-USER> #'+
#<FUNCTION +>
CL-USER> (funcall #'+ 2 3)
5

Функции более высокого порядка

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

CL-USER> (list 1 2 3)
(1 2 3)
CL-USER> (funcall #'list 1 2 3)
(1 2 3)
CL-USER> (funcall #'list 1 2 3 4 5)
(1 2 3 4 5)
CL-USER> (apply #'list '(1 2 3))
(1 2 3)
CL-USER> (apply #'list 1 2 '(4 5))
(1 2 3 4 5)
CL-USER> (apply #'+ 1 (list 2 3))
6
CL-USER> (defun my-funcall (function &rest args)
           (apply function args))
MY-FUNCALL
CL-USER> (my-funcall #'list 1 2 3)
(1 2 3)

Существует много других функций более высокого порядка, которые, например, многократно применяют функцию к элементам списка.

CL-USER> (map 'list #'/ '(1 2 3 4))
(1 1/2 1/3 1/4)
CL-USER> (map 'vector #'+ '(1 2 3 4 5) #(5 4 3 2 10))
#(6 6 6 6 15)
CL-USER> (reduce #'+ '(1 2 3 4 5))
15
CL-USER> (remove-if #'evenp '(1 2 3 4 5))
(1 3 5)

Подведение итогов

Функция сокращения может использоваться для суммирования элементов в списке.

(reduce '+ '(1 2 3 4))
;;=> 10

По умолчанию сокращение выполняет лево-ассоциативное сокращение, что означает, что сумма 10 вычисляется как

(+ (+ (+ 1 2) 3) 4)

Первые два элемента сначала суммируются, а затем этот результат (3) добавляется к следующему элементу (3) для получения 6, который, в свою очередь, добавляется к 4, чтобы получить конечный результат.

Это безопаснее, чем использование apply (например, in (apply '+' (1 2 3 4)), потому что длина списка аргументов, которую можно передать для применения , ограничена (см. Call-arguments-limit ), и сокращение будет работать с функциями, которые принимают только два аргумента.

Указав аргумент ключевого слова from-end , reduce будет обрабатывать список в другом направлении, что означает, что сумма вычисляется в обратном порядке. То есть

(reduce '+ (1 2 3 4) :from-end t)
;;=> 10

вычисляет

(+ 1 (+ 2 (+ 3 4)))

Внедрение реверса и аннулирования

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

(1 2 3) === (cons 1 (cons 2 (cons 3 '())))

обратный список

(cons 3 (cons 2 (cons 1 '()))) === (3 2 1)

Это может быть не очевидное использование сокращения , но если у нас есть функция «обратного cons», скажем xcons , такая, что

(xcons 1 2) === (2 . 1)

затем

(xcons (xcons (xcons () 1) 2) 3)

что является уменьшением.

(reduce (lambda (x y)
          (cons y x))
        '(1 2 3 4)
        :initial-value '())
;=> (4 3 2 1)

Common Lisp имеет другую полезную функцию, revappend , которая представляет собой комбинацию reverse и append . Концептуально, он меняет список и добавляет его в какой-то хвост:

(revappend '(3 2 1) '(4 5 6))
;;=> (1 2 3 4 5 6)

Это также может быть реализовано с уменьшением . Это факт, это то же самое, что и реализация обратного выше, за исключением того, что начальное значение должно быть (4 5 6) вместо пустого списка.

(reduce (lambda (x y)
          (cons y x))
        '(3 2 1)
        :initial-value '(4 5 6))
;=> (1 2 3 4 5 6)

Затворы

Функции запоминают лексическую область действия, в которой они определены. Из-за этого мы можем заключить лямбду в задании закрытия.

(defvar *counter* (let ((count 0))
                    (lambda () (incf count))))

(funcall *counter*) ;; => 1
(funcall *counter*) ;; = 2

В приведенном выше примере переменная счетчика доступна только для анонимной функции. Это более отчетливо видно в следующем примере

(defvar *counter-1* (make-counter))
(defvar *counter-2* (make-counter))

(funcall *counter-1*) ;; => 1
(funcall *counter-1*) ;; => 2
(funcall *counter-2*) ;; => 1
(funcall *counter-1*) ;; => 3

Определение функций, выполняющих функции и возвращаемые функции

Простой пример:

CL-USER> (defun make-apply-twice (fun)
           "return a new function that applies twice the function`fun' to its argument"
           (lambda (x)
             (funcall fun (funcall fun x))))
MAKE-APPLY-TWICE
CL-USER> (funcall (make-apply-twice #'1+) 3)
5
CL-USER> (let ((pow4 (make-apply-twice (lambda (x) (* x x)))))
           (funcall pow4 3))
81

Классический пример функционального состава : ( fgh ) ( x ) = f ( g ( h ( x )):

CL-USER> (defun compose (&rest funs)
           "return a new function obtained by the functional compositions of the parameters"
           (if (null funs) 
               #'identity
               (let ((rest-funs (apply #'compose (rest funs))))
                 (lambda (x) (funcall (first funs) (funcall rest-funs x))))))
COMPOSE
CL-USER> (defun square (x) (* x x))
SQUARE
CL-USER> (funcall (compose #'square #'1+ #'square) 3)
100  ;; => equivalent to (square (1+ (square 3)))


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow