811 lines
28 KiB
HTML
811 lines
28 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta name="generator" content=
|
||
"HTML Tidy for HTML5 for Linux version 5.2.0">
|
||
<title>Functions</title>
|
||
<meta charset="utf-8">
|
||
<meta name="description" content="A collection of examples of using Common Lisp">
|
||
<meta name="viewport" content=
|
||
"width=device-width, initial-scale=1">
|
||
<link rel="icon" href=
|
||
"assets/cl-logo-blue.png"/>
|
||
<link rel="stylesheet" href=
|
||
"assets/style.css">
|
||
<script type="text/javascript" src=
|
||
"assets/highlight-lisp.js">
|
||
</script>
|
||
<script type="text/javascript" src=
|
||
"assets/jquery-3.2.1.min.js">
|
||
</script>
|
||
<script type="text/javascript" src=
|
||
"assets/jquery.toc/jquery.toc.min.js">
|
||
</script>
|
||
<script type="text/javascript" src=
|
||
"assets/toggle-toc.js">
|
||
</script>
|
||
|
||
<link rel="stylesheet" href=
|
||
"assets/github.css">
|
||
|
||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||
</head>
|
||
<body>
|
||
<h1 id="title-xs"><a href="index.html">The Common Lisp Cookbook</a> – Functions</h1>
|
||
<div id="logo-container">
|
||
<a href="index.html">
|
||
<img id="logo" src="assets/cl-logo-blue.png"/>
|
||
</a>
|
||
|
||
<div id="searchform-container">
|
||
<form onsubmit="duckSearch()" action="javascript:void(0)">
|
||
<input id="searchField" type="text" value="" placeholder="Search...">
|
||
</form>
|
||
</div>
|
||
|
||
<div id="toc-container" class="toc-close">
|
||
<div id="toc-title">Table of Contents</div>
|
||
<ul id="toc" class="list-unstyled"></ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="content-container">
|
||
<h1 id="title-non-xs"><a href="index.html">The Common Lisp Cookbook</a> – Functions</h1>
|
||
|
||
<!-- Announcement we can keep for 1 month or more. I remove it and re-add it from time to time. -->
|
||
<!-- <p class="announce"> -->
|
||
<!-- 📢 🤶 ⭐ -->
|
||
<!-- <a style="font-size: 120%" href="https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPY-XMAS2023" title="This course is under a paywall on the Udemy platform. Several videos are freely available so you can judge before diving in. vindarel is (I am) the main contributor to this Cookbook."> Discover our contributor's Lisp course with this Christmas coupon.</a> -->
|
||
<!-- <strong> -->
|
||
<!-- Recently added: 18 videos on MACROS. -->
|
||
<!-- </strong> -->
|
||
<!-- <a style="font-size: 90%" href="https://github.com/vindarel/common-lisp-course-in-videos/">Learn more</a>. -->
|
||
<!-- </p> -->
|
||
|
||
<p class="announce">
|
||
📢 New videos: <a href="https://www.youtube.com/watch?v=h_noB1sI_e8">web dev demo part 1</a>, <a href="https://www.youtube.com/watch?v=xnwc7irnc8k">dynamic page with HTMX</a>, <a href="https://www.youtube.com/watch?v=Zpn86AQRVN8">Weblocks demo</a>
|
||
</p>
|
||
|
||
<p class="announce-neutral">
|
||
📕 <a href="index.html#download-in-epub">Get the EPUB and PDF</a>
|
||
</p>
|
||
|
||
|
||
<div id="content"
|
||
<p><a name="return"></a></p>
|
||
|
||
<h2 id="named-functions-defun">Named functions: <code>defun</code></h2>
|
||
|
||
<p>Creating named functions is done with the <code>defun</code> keyword. It follows this model:</p>
|
||
|
||
<pre><code class="language-lisp">(defun <name> (list of arguments)
|
||
"docstring"
|
||
(function body))
|
||
</code></pre>
|
||
|
||
<p>The return value is the value returned by the last expression of the body
|
||
(see below for more). There is no “return xx” statement.</p>
|
||
|
||
<p>So, for example:</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello-world ()
|
||
;; ^^ no arguments
|
||
(print "hello world!"))
|
||
</code></pre>
|
||
|
||
<p>Call it:</p>
|
||
|
||
<pre><code class="language-lisp">(hello-world)
|
||
;; "hello world!" <-- output
|
||
;; "hello world!" <-- a string is returned.
|
||
</code></pre>
|
||
|
||
<h2 id="arguments">Arguments</h2>
|
||
|
||
<h3 id="base-case-required-arguments">Base case: required arguments</h3>
|
||
|
||
<p>Add in arguments like this:</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello (name)
|
||
"Say hello to `name'."
|
||
(format t "hello ~a !~&" name))
|
||
;; HELLO
|
||
</code></pre>
|
||
|
||
<p>(where <code>~a</code> is the most used <code>format</code> directive to print a variable
|
||
<em>aesthetically</em> and <code>~&</code> prints a newline)</p>
|
||
|
||
<p>Call the function:</p>
|
||
|
||
<pre><code class="language-lisp">(hello "me")
|
||
;; hello me ! <-- this is printed by `format`
|
||
;; NIL <-- return value: `format t` prints a string
|
||
;; to standard output and returns nil.
|
||
</code></pre>
|
||
|
||
<p>If you don’t specify the right amount of arguments, you’ll be trapped
|
||
into the interactive debugger with an explicit error message:</p>
|
||
|
||
<p>(hello)</p>
|
||
|
||
<blockquote>
|
||
<p>invalid number of arguments: 0</p>
|
||
</blockquote>
|
||
|
||
<h3 id="optional-arguments-optional">Optional arguments: <code>&optional</code></h3>
|
||
|
||
<p>Optional arguments are declared after the <code>&optional</code> keyword in the
|
||
lambda list. They are ordered, they must appear one after another.</p>
|
||
|
||
<p>This function:</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello (name &optional age gender) …)
|
||
</code></pre>
|
||
|
||
<p>must be called like this:</p>
|
||
|
||
<pre><code class="language-lisp">(hello "me") ;; a value for the required argument,
|
||
;; zero optional arguments
|
||
(hello "me" "7") ;; a value for age
|
||
(hello "me" 7 :h) ;; a value for age and gender
|
||
</code></pre>
|
||
|
||
<h3 id="named-parameters-key">Named parameters: <code>&key</code></h3>
|
||
|
||
<p>It is not always convenient to remember the order of the arguments. It
|
||
is thus possible to supply arguments by name: we declare them using
|
||
<code>&key <name></code>, we set them with <code>:name <value></code> in the function call,
|
||
and we use <code>name</code> as a regular variable in the function body. They are
|
||
<code>nil</code> by default.</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello (name &key happy)
|
||
"If `happy' is `t', print a smiley"
|
||
(format t "hello ~a " name)
|
||
(when happy
|
||
(format t ":)~&")))
|
||
</code></pre>
|
||
|
||
<p>The following calls are possible:</p>
|
||
|
||
<pre><code>(hello "me")
|
||
(hello "me" :happy t)
|
||
(hello "me" :happy nil) ;; useless, equivalent to (hello "me")
|
||
</code></pre>
|
||
|
||
<p>and this is not valid: <code>(hello "me" :happy)</code>:</p>
|
||
|
||
<blockquote>
|
||
<p>odd number of &KEY arguments</p>
|
||
</blockquote>
|
||
|
||
<p>A similar example of a function declaration, with several key parameters:</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello (name &key happy lisper cookbook-contributor-p) …)
|
||
</code></pre>
|
||
|
||
<p>it can be called with zero or more key parameters, in any order:</p>
|
||
|
||
<pre><code class="language-lisp">(hello "me" :lisper t)
|
||
(hello "me" :lisper t :happy t)
|
||
(hello "me" :cookbook-contributor-p t :happy t)
|
||
</code></pre>
|
||
|
||
<p>Last but not least, you would quickly realize it, but we can choose the keys programmatically (they can be variables):</p>
|
||
|
||
<pre><code class="language-lisp">(let ((key :happy)
|
||
(val t))
|
||
(hello "me" key val))
|
||
;; hello me :)
|
||
;; NIL
|
||
</code></pre>
|
||
|
||
<h4 id="mixing-optional-and-key-parameters">Mixing optional and key parameters</h4>
|
||
|
||
<p>It is generally a style warning, but it is possible.</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello (&optional name &key happy)
|
||
(format t "hello ~a " name)
|
||
(when happy
|
||
(format t ":)~&")))
|
||
</code></pre>
|
||
|
||
<p>In SBCL, this yields:</p>
|
||
|
||
<pre><code>; in: DEFUN HELLO
|
||
; (SB-INT:NAMED-LAMBDA HELLO
|
||
; (&OPTIONAL NAME &KEY HAPPY)
|
||
; (BLOCK HELLO (FORMAT T "hello ~a " NAME) (WHEN HAPPY (FORMAT T ":)~&"))))
|
||
;
|
||
; caught STYLE-WARNING:
|
||
; &OPTIONAL and &KEY found in the same lambda list: (&OPTIONAL (NAME "John") &KEY
|
||
; HAPPY)
|
||
;
|
||
; compilation unit finished
|
||
; caught 1 STYLE-WARNING condition
|
||
</code></pre>
|
||
|
||
<p>We can call it:</p>
|
||
|
||
<pre><code class="language-lisp">(hello "me" :happy t)
|
||
;; hello me :)
|
||
;; NIL
|
||
</code></pre>
|
||
|
||
<h3 id="default-values-to-key-parameters">Default values to key parameters</h3>
|
||
|
||
<p>In the lambda list, use pairs to give a default value to an optional or a key argument, like <code>(happy t)</code> below:</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello (name &key (happy t))
|
||
</code></pre>
|
||
|
||
<p>Now <code>happy</code> is true by default.</p>
|
||
|
||
<h3 id="was-a-key-parameter-specified">Was a key parameter specified?</h3>
|
||
|
||
<p>You can skip this tip for now if you want, but come back later to it as it can turn handy.</p>
|
||
|
||
<p>We saw that a default key parameter is <code>nil</code> by default (<code>(defun hello
|
||
(name &key happy) …)</code>). But how can be distinguish between “the value
|
||
is NIL by default” and “the user wants it to be NIL”?</p>
|
||
|
||
<p>We saw how to use a tuple to set its default value:</p>
|
||
|
||
<p><code>&key (:happy t)</code></p>
|
||
|
||
<p>To answer our question, use a triple like this:</p>
|
||
|
||
<p><code>&key (happy t happy-p)</code></p>
|
||
|
||
<p>where <code>happy-p</code> serves as a <em>predicate</em> variable (using <code>-p</code> is only a
|
||
convention, give it the name you want) to know if the key was
|
||
supplied. If it was, then it will be <code>T</code>.</p>
|
||
|
||
<p>So now, we will print a sad face if <code>:happy</code> was explicitely set to
|
||
NIL. We don’t print it by default.</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello (name &key (happy nil happy-p))
|
||
(format t "Key supplied? ~a~&" happy-p)
|
||
(format t "hello ~a " name)
|
||
(when happy-p
|
||
(if happy
|
||
(format t ":)")
|
||
(format t ":("))))
|
||
</code></pre>
|
||
|
||
<h3 id="variable-number-of-arguments-rest">Variable number of arguments: <code>&rest</code></h3>
|
||
|
||
<p>Sometimes you want a function to accept a variable number of
|
||
arguments. Use <code>&rest <variable></code>, where <code><variable></code> will be a list.</p>
|
||
|
||
<pre><code class="language-lisp">(defun mean (x &rest numbers)
|
||
(/ (apply #'+ x numbers)
|
||
(1+ (length numbers))))
|
||
</code></pre>
|
||
|
||
<pre><code class="language-lisp">(mean 1)
|
||
(mean 1 2) ;; => 3/2 (yes, it is printed as a ratio)
|
||
(mean 1 2 3 4 5) ;; => 3
|
||
</code></pre>
|
||
|
||
<h3 id="defining-key-arguments-and-allowing-more-allow-other-keys">Defining key arguments, and allowing more: <code>&allow-other-keys</code></h3>
|
||
|
||
<p>Observe:</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello (name &key happy)
|
||
(format t "hello ~a~&" name))
|
||
|
||
(hello "me" :lisper t)
|
||
;; => Error: unknown keyword argument
|
||
</code></pre>
|
||
|
||
<p>whereas</p>
|
||
|
||
<pre><code class="language-lisp">(defun hello (name &key happy &allow-other-keys)
|
||
(format t "hello ~a~&" name))
|
||
|
||
(hello "me" :lisper t)
|
||
;; hello me
|
||
</code></pre>
|
||
|
||
<p>We might need <code>&allow-other-keys</code> when passing around arguments or
|
||
with higher level manipulation of functions.</p>
|
||
|
||
<p>Here’s a real example. We define a function to open a file that always
|
||
uses <code>:if-exists :supersede</code>, but still passes any other keys to the
|
||
<code>open</code> function.</p>
|
||
|
||
<pre><code class="language-lisp">(defun open-supersede (f &rest other-keys &key &allow-other-keys)
|
||
(apply #'open f :if-exists :supersede other-keys))
|
||
</code></pre>
|
||
|
||
<p>In the case of a duplicated <code>:if-exists</code> argument, our first one takes precedence.</p>
|
||
|
||
<h2 id="return-values">Return values</h2>
|
||
|
||
<p>The return value of the function is the value returned by the last
|
||
executed form of the body.</p>
|
||
|
||
<p>There are ways for non-local exits (<code>return-from <function name> <value></code>), but they are usually not needed.</p>
|
||
|
||
<p>Common Lisp has also the concept of multiple return values.</p>
|
||
|
||
<h3 id="multiple-return-values-values-multiple-value-bind-and-nth-value">Multiple return values: <code>values</code>, <code>multiple-value-bind</code> and <code>nth-value</code></h3>
|
||
|
||
<p>Returning multiple values is <em>not</em> like returning a tuple or a list of
|
||
results ;) This is a common misconception.</p>
|
||
|
||
<p>Multiple values are specially useful and powerful because a change in
|
||
them needs little to no refactoring.</p>
|
||
|
||
<pre><code class="language-lisp">(defun foo (a b c)
|
||
a)
|
||
</code></pre>
|
||
|
||
<p>This function returns <code>a</code>.</p>
|
||
|
||
<pre><code class="language-lisp">(defvar *res* (foo :a :b :c))
|
||
;; :A
|
||
</code></pre>
|
||
|
||
<p>We use <code>values</code> to return multiple values:</p>
|
||
|
||
<pre><code class="language-lisp">(defun foo (a b c)
|
||
(values a b c))
|
||
</code></pre>
|
||
|
||
<pre><code class="language-lisp">(setf *res* (foo :a :b :c))
|
||
;; :A
|
||
</code></pre>
|
||
|
||
<p>Observe here that <code>*res*</code> <em>is still <code>:A</code></em>.</p>
|
||
|
||
<p>All functions that use the return value of <code>foo</code> need <em>not</em> to change, they
|
||
still work. If we had returned a list or an array, this would be
|
||
different.</p>
|
||
|
||
<p><strong>multiple-value-bind</strong></p>
|
||
|
||
<p>We destructure multiple values with <code>multiple-value-bind</code> (or
|
||
<code>mvb</code>+TAB in Slime for short) and we can get one given its position
|
||
with <code>nth-value</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(multiple-value-bind (res1 res2 res3)
|
||
(foo :a :b :c)
|
||
(format t "res1 is ~a, res2 is ~a, res2 is ~a~&"
|
||
res1 res2 res3))
|
||
;; res1 is A, res2 is B, res2 is C
|
||
;; NIL
|
||
</code></pre>
|
||
|
||
<p>Its general form is</p>
|
||
|
||
<pre><code class="language-lisp">(multiple-value-bind (var-1 .. var-n) expr
|
||
body)
|
||
</code></pre>
|
||
|
||
<p>The variables <code>var-n</code> are not available outside the scope of <code>multiple-value-bind</code>.</p>
|
||
|
||
<p>With <strong>nth-value</strong>:</p>
|
||
|
||
<pre><code class="language-lisp">(nth-value 0 (values :a :b :c)) ;; => :A
|
||
(nth-value 2 (values :a :b :c)) ;; => :C
|
||
(nth-value 9 (values :a :b :c)) ;; => NIL
|
||
</code></pre>
|
||
|
||
<p>Look here too that <code>values</code> is different from a list:</p>
|
||
|
||
<pre><code class="language-lisp">(nth-value 0 '(:a :b :c)) ;; => (:A :B :C)
|
||
(nth-value 1 '(:a :b :c)) ;; => NIL
|
||
</code></pre>
|
||
|
||
<p>Note that <code>(values)</code> with no values returns… no values at all.</p>
|
||
|
||
<p><strong>multiple-value-list</strong></p>
|
||
|
||
<p>While we are at it: <a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_mult_1.htm">multiple-value-list</a> turns multiple values to a list:</p>
|
||
|
||
<pre><code class="language-lisp">(multiple-value-list (values 1 2 3))
|
||
;; (1 2 3)
|
||
</code></pre>
|
||
|
||
<p>The reverse is <strong>values-list</strong>, it turns a list to multiple values:</p>
|
||
|
||
<pre><code class="language-lisp">(values-list '(1 2 3))
|
||
;; 1
|
||
;; 2
|
||
;; 3
|
||
</code></pre>
|
||
|
||
<h2 id="anonymous-functions-lambda">Anonymous functions: <code>lambda</code></h2>
|
||
|
||
<p>Anonymous functions are created with <code>lambda</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(lambda (x) (print x))
|
||
</code></pre>
|
||
|
||
<p>We can call a lambda with <code>funcall</code> or <code>apply</code> (see below).</p>
|
||
|
||
<p>If the first element of an unquoted list is a lambda expression, the
|
||
lambda is called:</p>
|
||
|
||
<pre><code class="language-lisp">((lambda (x) (print x)) "hello")
|
||
;; hello
|
||
</code></pre>
|
||
|
||
<h2 id="calling-functions-programmatically-funcall-and-apply">Calling functions programmatically: <code>funcall</code> and <code>apply</code></h2>
|
||
|
||
<p><code>funcall</code> is to be used with a known number of arguments, when <code>apply</code>
|
||
can be used on a list, for example from <code>&rest</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(funcall #'+ 1 2)
|
||
(apply #'+ '(1 2))
|
||
</code></pre>
|
||
|
||
<h3 id="referencing-functions-by-name-single-quote--or-sharpsign-quote-">Referencing functions by name: single quote <code>'</code> or sharpsign-quote <code>#'</code>?</h3>
|
||
|
||
<p>In the example above, we used <code>#'</code>, but a single quote also works, and
|
||
we can encounter it in the wild. Which one to use?</p>
|
||
|
||
<p>It is generally safer to use <code>#'</code>, because it respects lexical scope. Observe:</p>
|
||
|
||
<pre><code class="language-lisp">(defun foo (x)
|
||
(* x 100))
|
||
|
||
(flet ((foo (x) (1+ x)))
|
||
(funcall #'foo 1))
|
||
;; => 2, as expected
|
||
|
||
;; But:
|
||
|
||
(flet ((foo (x) (1+ x)))
|
||
(funcall 'foo 1))
|
||
;; => 100
|
||
</code></pre>
|
||
|
||
<p><code>#'</code> is actually the shorthand for <code>(function …)</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(function +)
|
||
;; #<FUNCTION +>
|
||
|
||
(flet ((foo (x) (1+ x)))
|
||
(print (function foo))
|
||
(funcall (function foo) 1))
|
||
;; #<FUNCTION (FLET FOO) {1001C0ACFB}>
|
||
;; 2
|
||
</code></pre>
|
||
|
||
<p>Using <code>function</code> or the <code>#'</code> shorthand allows us to refer to local
|
||
functions. If we pass instead a symbol to <code>funcall</code>, what is
|
||
called is always the function named by that symbol in the <em>global environment</em>.</p>
|
||
|
||
<p>In addition, <code>#'</code> catches the function by value. If the function is redefined, bindings that refered to this function by <code>#'</code> will still run its original behaviour.</p>
|
||
|
||
<p>Let’s assign a function to a parameter:</p>
|
||
|
||
<pre><code class="language-lisp">(defparameter *foo-caller* #'foo)
|
||
(funcall *foo-caller* 1)
|
||
;; => 100
|
||
</code></pre>
|
||
|
||
<p>Now, if we redefine <code>foo</code>, the behaviour of <code>*foo-caller*</code> will <em>not</em> change:</p>
|
||
|
||
<pre><code class="language-lisp">(defun foo (x) (1+ x))
|
||
;; WARNING: redefining CL-USER::FOO in DEFUN
|
||
;; FOO
|
||
|
||
(funcall *foo-caller* 1)
|
||
;; 100 ;; and not 2
|
||
</code></pre>
|
||
|
||
<p>If we bind the caller with <code>'foo</code>, a single quote, the function will be resolved at runtime:</p>
|
||
|
||
<pre><code class="language-lisp">(defun foo (x) (* x 100)) ;; back to original behavior.
|
||
(defparameter *foo-caller-2* 'foo)
|
||
;; *FOO-CALLER-2*
|
||
(funcall *foo-caller-2* 1)
|
||
;; 100
|
||
|
||
;; We change the definition:
|
||
(defun foo (x) (1+ x))
|
||
;; WARNING: redefining CL-USER::FOO in DEFUN
|
||
;; FOO
|
||
|
||
;; We try again:
|
||
(funcall *foo-caller-2* 1)
|
||
;; 2
|
||
</code></pre>
|
||
|
||
<p>The behaviour you want depends on your use case. Generally, using sharpsign-quote is less surprising. But if you are running a tight loop and you want live-update mechanisms (think a game or live visualisations), you might want to use a single quote so that your loop picks up the user’s new function definition.</p>
|
||
|
||
<h2 id="higher-order-functions-functions-that-return-functions">Higher order functions: functions that return functions</h2>
|
||
|
||
<p>Writing functions that return functions is simple enough:</p>
|
||
|
||
<pre><code class="language-lisp">(defun adder (n)
|
||
(lambda (x) (+ x n)))
|
||
;; ADDER
|
||
</code></pre>
|
||
|
||
<p>Here we have defined the function <code>adder</code> which returns an <em>object</em> of <em>type</em> <a href="http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm"><code>function</code></a>.</p>
|
||
|
||
<p>To call the resulting function, we must use <code>funcall</code> or <code>apply</code>:</p>
|
||
|
||
<pre><code class="language-lisp">(adder 5)
|
||
;; #<CLOSURE (LAMBDA (X) :IN ADDER) {100994ACDB}>
|
||
(funcall (adder 5) 3)
|
||
;; 8
|
||
</code></pre>
|
||
|
||
<p>Trying to call it right away leads to an illegal function call:</p>
|
||
|
||
<pre><code class="language-lisp">((adder 3) 5)
|
||
In: (ADDER 3) 5
|
||
((ADDER 3) 5)
|
||
Error: Illegal function call.
|
||
</code></pre>
|
||
|
||
<p>Indeed, CL has different <em>namespaces</em> for functions and variables, i.e. the same <em>name</em> can refer to different things depending on its position in a form that’s evaluated.</p>
|
||
|
||
<pre><code class="language-lisp">;; The symbol foo is bound to nothing:
|
||
CL-USER> (boundp 'foo)
|
||
NIL
|
||
CL-USER> (fboundp 'foo)
|
||
NIL
|
||
;; We create a variable:
|
||
CL-USER> (defparameter foo 42)
|
||
FOO
|
||
* foo
|
||
42
|
||
;; Now foo is "bound":
|
||
CL-USER> (boundp 'foo)
|
||
T
|
||
;; but still not as a function:
|
||
CL-USER> (fboundp 'foo)
|
||
NIL
|
||
;; So let's define a function:
|
||
CL-USER> (defun foo (x) (* x x))
|
||
FOO
|
||
;; Now the symbol foo is bound as a function too:
|
||
CL-USER> (fboundp 'foo)
|
||
T
|
||
;; Get the function:
|
||
CL-USER> (function foo)
|
||
#<FUNCTION FOO>
|
||
;; and the shorthand notation:
|
||
* #'foo
|
||
#<FUNCTION FOO>
|
||
;; We call it:
|
||
(funcall (function adder) 5)
|
||
#<CLOSURE (LAMBDA (X) :IN ADDER) {100991761B}>
|
||
;; and call the lambda:
|
||
(funcall (funcall (function adder) 5) 3)
|
||
8
|
||
</code></pre>
|
||
|
||
<p>To simplify a bit, you can think of each symbol in CL having (at least) two “cells” in which information is stored. One cell - sometimes referred to as its <em>value cell</em> - can hold a value that is <em>bound</em> to this symbol, and you can use <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_boundp.htm"><code>boundp</code></a> to test whether the symbol is bound to a value (in the global environment). You can access the value cell of a symbol with <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_symb_5.htm"><code>symbol-value</code></a>.</p>
|
||
|
||
<p>The other cell - sometimes referred to as its <em>function cell</em> - can hold the definition of the symbol’s (global) function binding. In this case, the symbol is said to be <em>fbound</em> to this definition. You can use <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_fbound.htm"><code>fboundp</code></a> to test whether a symbol is fbound. You can access the function cell of a symbol (in the global environment) with <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_symb_1.htm"><code>symbol-function</code></a>.</p>
|
||
|
||
<p>Now, if a <em>symbol</em> is evaluated, it is treated as a <em>variable</em> in that its value cell is returned (just <code>foo</code>). If a <em>compound form</em>, i.e. a <em>cons</em>, is evaluated and its <em>car</em> is a symbol, then the function cell of this symbol is used (as in <code>(foo 3)</code>).</p>
|
||
|
||
<p>In Common Lisp, as opposed to Scheme, it is <em>not</em> possible that the car of the compound form to be evaluated is an arbitrary form. If it is not a symbol, it <em>must</em> be a <em>lambda expression</em>, which looks like <code>(lambda </code><em>lambda-list</em> <em>form*</em><code>)</code>.</p>
|
||
|
||
<p>This explains the error message we got above - <code>(adder 3)</code> is neither a symbol nor a lambda expression.</p>
|
||
|
||
<p>If we want to be able to use the symbol <code>*my-fun*</code> in the car of a compound form, we have to explicitly store something in its <em>function cell</em> (which is normally done for us by the macro <a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_defun.htm"><code>defun</code></a>):</p>
|
||
|
||
<pre><code class="language-lisp">;;; continued from above
|
||
CL-USER> (fboundp '*my-fun*)
|
||
NIL
|
||
CL-USER> (setf (symbol-function '*my-fun*) (adder 3))
|
||
#<CLOSURE (LAMBDA (X) :IN ADDER) {10099A5EFB}>
|
||
CL-USER> (fboundp '*my-fun*)
|
||
T
|
||
CL-USER> (*my-fun* 5)
|
||
8
|
||
</code></pre>
|
||
|
||
<p>Read the CLHS section about <a href="http://www.lispworks.com/documentation/HyperSpec/Body/03_aba.htm">form evaluation</a> for more.</p>
|
||
|
||
<h2 id="closures">Closures</h2>
|
||
|
||
<p>Closures allow to capture lexical bindings:</p>
|
||
|
||
<pre><code class="language-lisp">(let ((limit 3)
|
||
(counter -1))
|
||
(defun my-counter ()
|
||
(if (< counter limit)
|
||
(incf counter)
|
||
(setf counter 0))))
|
||
|
||
(my-counter)
|
||
0
|
||
(my-counter)
|
||
1
|
||
(my-counter)
|
||
2
|
||
(my-counter)
|
||
3
|
||
(my-counter)
|
||
0
|
||
</code></pre>
|
||
|
||
<p>Or similarly:</p>
|
||
|
||
<pre><code class="language-lisp">(defun repeater (n)
|
||
(let ((counter -1))
|
||
(lambda ()
|
||
(if (< counter n)
|
||
(incf counter)
|
||
(setf counter 0)))))
|
||
|
||
(defparameter *my-repeater* (repeater 3))
|
||
;; *MY-REPEATER*
|
||
(funcall *my-repeater*)
|
||
0
|
||
(funcall *my-repeater*)
|
||
1
|
||
(funcall *my-repeater*)
|
||
2
|
||
(funcall *my-repeater*)
|
||
3
|
||
(funcall *my-repeater*)
|
||
0
|
||
</code></pre>
|
||
|
||
<p>See more on <a href="http://www.gigamonkeys.com/book/variables.html">Practical Common Lisp</a>.</p>
|
||
|
||
<h2 id="setf-functions"><code>setf</code> functions</h2>
|
||
|
||
<p>A function name can also be a list of two symbols with <code>setf</code> as the
|
||
first one, and where the first argument is the new value:</p>
|
||
|
||
<pre><code class="language-lisp">(defun (setf <name>) (new-value <other arguments>)
|
||
body)
|
||
</code></pre>
|
||
|
||
<p>This mechanism is often used for CLOS methods.</p>
|
||
|
||
<p>Let’s work towards an example. Let’s say we manipulate a hash-table
|
||
that represents a square. We store the square width in this
|
||
hash-table:</p>
|
||
|
||
<pre><code class="language-lisp">(defparameter *square* (make-hash-table))
|
||
(setf (gethash :width *square*) 21)
|
||
</code></pre>
|
||
|
||
<p>During our program life cycle, we can change the square width, with <code>setf</code> as we did above.</p>
|
||
|
||
<p>We define a function to compute a square area. We don’t store it in
|
||
the hash-table as it is redundant with the dimension.</p>
|
||
|
||
<pre><code class="language-lisp">(defun area (square)
|
||
(expt (gethash :width square) 2))
|
||
</code></pre>
|
||
|
||
<p>Now, our programming needs lead to the situation where it would be
|
||
very handy to change the <em>area</em> of the square… and have this reflected
|
||
on the square’s dimensions. It can be ergonomic for your program’s
|
||
application interface to define a setf-function, like this:</p>
|
||
|
||
<pre><code class="language-lisp">(defun (setf area) (new-area square)
|
||
(let ((width (sqrt new-area)))
|
||
(setf (gethash :width square) width)))
|
||
</code></pre>
|
||
|
||
<p>And now you can do:</p>
|
||
|
||
<pre><code class="language-lisp">(setf (area *SQUARE*) 100)
|
||
;; => 10.0
|
||
</code></pre>
|
||
|
||
<p>and check your square (<code>describe</code>, <code>inspect</code>…), the new width was set.</p>
|
||
|
||
<h2 id="currying">Currying</h2>
|
||
|
||
<h3 id="concept">Concept</h3>
|
||
|
||
<p>A related concept is that of <em><a href="https://en.wikipedia.org/wiki/Currying">currying</a></em> which you might be familiar with if you’re coming from a functional language. After we’ve read the last section that’s rather easy to implement:</p>
|
||
|
||
<pre><code class="language-lisp">CL-USER> (defun curry (function &rest args)
|
||
(lambda (&rest more-args)
|
||
(apply function (append args more-args))))
|
||
CURRY
|
||
CL-USER> (funcall (curry #'+ 3) 5)
|
||
8
|
||
CL-USER> (funcall (curry #'+ 3) 6)
|
||
9
|
||
CL-USER> (setf (symbol-function 'power-of-ten) (curry #'expt 10))
|
||
#<Interpreted Function "LAMBDA (FUNCTION &REST ARGS)" {482DB969}>
|
||
CL-USER> (power-of-ten 3)
|
||
1000
|
||
</code></pre>
|
||
|
||
<h3 id="with-the-alexandria-library">With the Alexandria library</h3>
|
||
|
||
<p>Now that you know how to do it, you may appreciate using the
|
||
implementation of the
|
||
<a href="https://common-lisp.net/project/alexandria/draft/alexandria.html#Data-and-Control-Flow">Alexandria</a>
|
||
library (in Quicklisp).</p>
|
||
|
||
<pre><code class="language-lisp">(ql:quickload "alexandria")
|
||
|
||
(defun adder (foo bar)
|
||
"Add the two arguments."
|
||
(+ foo bar))
|
||
|
||
(defvar add-one (alexandria:curry #'adder 1) "Add 1 to the argument.")
|
||
|
||
(funcall add-one 10) ;; => 11
|
||
|
||
(setf (symbol-function 'add-one) add-one)
|
||
(add-one 10) ;; => 11
|
||
</code></pre>
|
||
|
||
<h2 id="documentation">Documentation</h2>
|
||
|
||
<ul>
|
||
<li>functions: http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm#function</li>
|
||
<li>ordinary lambda lists: http://www.lispworks.com/documentation/HyperSpec/Body/03_da.htm</li>
|
||
<li>multiple-value-bind: http://clhs.lisp.se/Body/m_multip.htm</li>
|
||
</ul>
|
||
|
||
|
||
<p class="page-source">
|
||
Page source: <a href="https://github.com/LispCookbook/cl-cookbook/blob/master/functions.md">functions.md</a>
|
||
</p>
|
||
</div>
|
||
|
||
<script type="text/javascript">
|
||
|
||
// Don't write the TOC on the index.
|
||
if (window.location.pathname != "/cl-cookbook/") {
|
||
$("#toc").toc({
|
||
content: "#content", // will ignore the first h1 with the site+page title.
|
||
headings: "h1,h2,h3,h4"});
|
||
}
|
||
|
||
$("#two-cols + ul").css({
|
||
"column-count": "2",
|
||
});
|
||
$("#contributors + ul").css({
|
||
"column-count": "4",
|
||
});
|
||
</script>
|
||
|
||
|
||
|
||
<div>
|
||
<footer class="footer">
|
||
<hr/>
|
||
© 2002–2023 the Common Lisp Cookbook Project
|
||
<div>
|
||
📹 Discover <a style="color: darkgrey; text-decoration: underline", href="https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358">our contributor's Common Lisp video course on Udemy</a>
|
||
</div>
|
||
</footer>
|
||
|
||
</div>
|
||
<div id="toc-btn">T<br>O<br>C</div>
|
||
</div>
|
||
|
||
<script text="javascript">
|
||
HighlightLisp.highlight_auto({className: null});
|
||
</script>
|
||
|
||
<script type="text/javascript">
|
||
function duckSearch() {
|
||
var searchField = document.getElementById("searchField");
|
||
if (searchField && searchField.value) {
|
||
var query = escape("site:lispcookbook.github.io/cl-cookbook/ " + searchField.value);
|
||
window.location.href = "https://duckduckgo.com/?kj=b2&kf=-1&ko=1&q=" + query;
|
||
// https://duckduckgo.com/params
|
||
// kj=b2: blue header in results page
|
||
// kf=-1: no favicons
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<script async defer data-domain="lispcookbook.github.io/cl-cookbook" src="https://plausible.io/js/plausible.js"></script>
|
||
|
||
</body>
|
||
</html>
|