common-lisp
첫 번째 클래스 값으로 함수
수색…
통사론
- (함수 이름); 그 이름의 함수 객체를 검색한다.
- # '이름; 통사론 (함수명)
- (기호 - 기능 기호); symbol에 바인딩 된 함수를 반환합니다.
- (funcall 함수 args ...); args로 함수 호출하기
- (함수 arglist 적용); 리스트에 주어진 인자를 가진 함수를 호출한다.
- (함수 arg1 arg2 ... argn arglist 적용); arg1, arg2, ..., argn에 의해 주어진 인자를 가진 함수를 호출하고 나머지는 arglist에 넣는다.
매개 변수
매개 변수 | 세부 |
---|---|
이름 | 함수의 이름을 짓는 일부 (평가되지 않은) 기호 |
상징 | 상징 |
기능 | 호출 될 함수 |
args ... | 0 개 이상의 인수 (인수하지리스트) |
arglist | 함수에 전달할 인수가 들어있는 목록 |
arg1, arg2, ..., argn | 각 함수는 함수에 전달할 단일 인수입니다. |
비고
Lisp과 비슷한 언어에 대해서 이야기 할 때, Lisp-1과 Lisp-2로 알려진 것을 공통적으로 구분합니다. Lisp-1에서 기호는 값을 가지고 있고 기호가 함수를 참조하면 그 기호의 값은 그 함수가됩니다. Lisp-2에서 기호는 별도의 연관된 값과 함수를 가질 수 있으므로 값 대신 기호에 저장된 함수를 참조하려면 특수 형식이 필요합니다.
Common Lisp는 기본적으로 Lisp-2이지만 실제로 심볼이 참조 할 수있는 것 이상의 2 개의 네임 스페이스가 있습니다. - 심볼은 값, 함수, 유형 및 태그를 참조 할 수 있습니다.
익명 함수 정의하기
Common Lisp의 함수는 퍼스트 클래스 값 입니다. 익명 함수는 lambda
를 사용하여 만들 수 있습니다. 예를 들어, 다음은 funcall
사용하여 호출하는 3 개의 인수의 함수입니다.
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)
예를 들어 목록의 요소에 여러 번 함수를 적용하는 많은 다른 higher-order 함수가 있습니다.
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 함수를 사용하여 목록의 요소를 합할 수 있습니다.
(reduce '+ '(1 2 3 4))
;;=> 10
기본적으로 reduce 는 왼쪽 연관 감소를 수행합니다. 즉, 합계 10은 다음과 같이 계산됩니다.
(+ (+ (+ 1 2) 3) 4)
첫 번째 두 요소가 먼저 합산 된 다음 결과 (3)가 다음 요소 (3)에 추가되어 6이 생성되고, 마지막 요소 인 4가 최종 결과를 생성합니다.
이것은 ( '+'적용에서, 예를 들어 (적용하여보다 안전 (1 2 3 적용에 전달 될 수있는 인수 목록의 길이가 제한되기 때문에 4)) (참조) 인수 제한-전화 및 작동 감소 두 개의 인수 만 취하는 함수가 있습니다.
from-end 키워드 인수를 지정하면 reduce 는 목록을 다른 방향으로 처리합니다. 즉, 합계가 역순으로 계산됩니다. 그건
(reduce '+ (1 2 3 4) :from-end t)
;;=> 10
컴퓨팅이다
(+ 1 (+ 2 (+ 3 4)))
리버스 구현 및 revappend 구현
Common Lisp는 이미 역순으로 기능을 가지고 있지만 그렇지 않다면 reduce를 사용하여 쉽게 구현 될 수 있습니다. 다음과 같은 목록이 주어집니다.
(1 2 3) === (cons 1 (cons 2 (cons 3 '())))
반전 된 목록은
(cons 3 (cons 2 (cons 1 '()))) === (3 2 1)
이는 감소 의 명백한 사용은 아니지만, 우리가 "반대 개념"인 경우, 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)
이것은 reduce 로 구현 될 수도 있습니다. 사실, 초기 값이 빈 목록 대신 (4 5 6) 이어야한다는 점을 제외하고 위의 역순으로 구현 한 것과 같습니다.
(reduce (lambda (x y)
(cons y x))
'(3 2 1)
:initial-value '(4 5 6))
;=> (1 2 3 4 5 6)
마감
함수는 정의 된 어휘 범위를 기억합니다.이 때문에 람다를 let에 묶어서 클로저를 정의 할 수 있습니다.
(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
고전적 예 함수 조성물 (F ∘ g ∘ H) (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)))