common-lisp
प्रथम श्रेणी के मूल्यों के रूप में कार्य
खोज…
वाक्य - विन्यास
- (फ़ंक्शन नाम); उस नाम के फ़ंक्शन ऑब्जेक्ट को पुनर्प्राप्त करता है
- # # नाम; के लिए वाक्य रचना चीनी (फ़ंक्शन नाम)
- (प्रतीक-समारोह प्रतीक); प्रतीक के लिए बाध्य फ़ंक्शन देता है
- (कवक समारोह args ...); आर्ग के साथ कॉल फ़ंक्शन
- (आवेदन समारोह arglist); किसी सूची में दिए गए तर्कों के साथ फ़ंक्शन करें
- (लागू फ़ंक्शन arg1 arg2 ... argn arglist); Arg1, arg2, ..., argn, और बाकी की सूची arglist द्वारा दिए गए तर्कों के साथ कॉल फ़ंक्शन
पैरामीटर
पैरामीटर | विवरण |
---|---|
नाम | कुछ (अविकसित) प्रतीक जो एक फ़ंक्शन का नाम देते हैं |
प्रतीक | एक प्रतीक |
समारोह | एक फ़ंक्शन जिसे कहा जाना है |
args ... | शून्य या अधिक तर्क (तर्कों की सूची नहीं ) |
arglist | एक सूची जिसमें तर्कों को एक समारोह में पारित किया जाना है |
arg1, arg2, ..., argn | प्रत्येक एक फ़ंक्शन को पास करने के लिए एक एकल तर्क है |
टिप्पणियों
जब लिस्प जैसी भाषाओं के बारे में बात की जाती है, तो लिस्प -1 और लिस्प -2 के रूप में जाना जाने वाला एक सामान्य अंतर है। लिस्प -1 में, प्रतीकों का केवल एक मूल्य होता है और यदि कोई प्रतीक किसी फ़ंक्शन को संदर्भित करता है तो उस प्रतीक का मान उस फ़ंक्शन का होगा। लिस्प -2 में, प्रतीकों में अलग-अलग संबद्ध मूल्य और कार्य हो सकते हैं और इसलिए मूल्य के बजाय प्रतीक में संग्रहीत फ़ंक्शन को संदर्भित करने के लिए एक विशेष रूप की आवश्यकता होती है।
आम लिस्प मूल रूप से एक लिस्प -2 है, हालांकि वास्तव में 2 से अधिक नामस्थान (ऐसी चीजें हैं जो प्रतीकों का उल्लेख कर सकते हैं) - उदाहरण के लिए मान, कार्य, प्रकार और टैग का उल्लेख कर सकते हैं।
अनाम कार्यों को परिभाषित करना
सामान्य लिस्प में कार्य प्रथम श्रेणी के मूल्य हैं । 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
बेनामी कार्यों को भी सीधे इस्तेमाल किया जा सकता है। आम लिस्प इसके लिए एक सिंटैक्स प्रदान करता है।
((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
उद्धृत लंबोदर भाव कार्य नहीं हैं
ध्यान दें कि लैम्ब्डा के भाव कॉमन लिस्प में कार्य नहीं हैं। यह काम नहीं करता है:
(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>
मौजूदा कार्यों का जिक्र
कॉमन लिस्प के किसी भी प्रतीक में एक वैरिएबल के लिए एक स्लॉट होता है और एक फंक्शन के लिए एक अलग स्लॉट होता है।
ध्यान दें कि इस उदाहरण में नामकरण केवल चित्रण के लिए है। वैश्विक चरों का नाम 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
उच्चतर कार्य
आम लिस्प में कई उच्च क्रम वाले कार्य होते हैं जो तर्कों के लिए पारित कार्य होते हैं और उन्हें कॉल करते हैं। शायद सबसे मौलिक 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 में जोड़ा जाता है।
यह लागू होने का उपयोग करने की तुलना में अधिक सुरक्षित है (उदाहरण के लिए, ('लागू करें' (1 2 3 4)) क्योंकि तर्क सूची की लंबाई जिसे लागू करने के लिए पारित किया जा सकता है, वह सीमित है ( कॉल-तर्क-सीमा देखें ), और कम काम करेगा उन कार्यों के साथ जो केवल दो तर्क देते हैं।
एंड-एंड कीवर्ड तर्क को निर्दिष्ट करके, सूची को दूसरी दिशा में कम कर देगा, जिसका अर्थ है कि राशि रिवर्स ऑर्डर में गणना की जाती है। अर्थात्
(reduce '+ (1 2 3 4) :from-end t)
;;=> 10
कंप्यूटिंग है
(+ 1 (+ 2 (+ 3 4)))
रिवर्स और पुन: लागू करना
आम लिस्प में पहले से ही एक रिवर्स फ़ंक्शन होता है, लेकिन अगर यह नहीं था, तो इसे कम करके आसानी से लागू किया जा सकता है। जैसी सूची दी
(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)
कॉमन लिस्प का एक और उपयोगी कार्य है, रिवापेंड , जो रिवर्स और एपेंड का एक संयोजन है। वैचारिक रूप से, यह एक सूची को उलट देता है और इसे कुछ पूंछ में जोड़ देता है:
(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
फ़ंक्शन संरचना का शास्त्रीय उदाहरण: ( f example 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)))