89 lines
No EOL
15 KiB
HTML
89 lines
No EOL
15 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
<title>CLiki: List Comprehension</title>
|
||
<link rel="alternate" type="application/atom+xml" title="ATOM feed of edits to current article"
|
||
href="https://www.cliki.net/site/feed/article.atom?title=List%20Comprehension">
|
||
<link rel="stylesheet" href="static/css/style.css">
|
||
<link rel="stylesheet" href="static/css/colorize.css">
|
||
</head>
|
||
|
||
<body>
|
||
<span class="hidden">CLiki - List Comprehension</span>
|
||
<div id="content"><div id="content-area"><div id="article-title">List Comprehension</div><div id="article">Refer to Wikipedia's article on <a href="https://en.wikipedia.org/wiki/List_comprehension">List Comprehension</a>.<p><h2>Example</h2><p>The following is a typical example of the usage of list comprehension:<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_setf.html" class="symbol">setf</a> l '<span class="paren2">(<span class="nonparen">1 2 3 4 5 6 7 8 9 10</span>)</span></span>)</span>
|
||
|
||
<span class="paren1">(<span class="nonparen">collect-list <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a> x y</span>)</span>
|
||
<span class="paren2">(<span class="nonparen">for x in l</span>)</span>
|
||
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_evenpcm_oddp.html" class="symbol">evenp</a> x</span>)</span>
|
||
<span class="paren2">(<span class="nonparen">for y in l</span>)</span>
|
||
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_evenpcm_oddp.html" class="symbol">oddp</a> y</span>)</span></span>)</span></span></div><p>⇒<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><span class="paren2">(<span class="nonparen">2 1</span>)</span> <span class="paren2">(<span class="nonparen">2 3</span>)</span> <span class="paren2">(<span class="nonparen">2 5</span>)</span> <span class="paren2">(<span class="nonparen">2 7</span>)</span> <span class="paren2">(<span class="nonparen">2 9</span>)</span> <span class="paren2">(<span class="nonparen">4 1</span>)</span> <span class="paren2">(<span class="nonparen">4 3</span>)</span> <span class="paren2">(<span class="nonparen">4 5</span>)</span> <span class="paren2">(<span class="nonparen">4 7</span>)</span> <span class="paren2">(<span class="nonparen">4 9</span>)</span> <span class="paren2">(<span class="nonparen">6 1</span>)</span> <span class="paren2">(<span class="nonparen">6 3</span>)</span> <span class="paren2">(<span class="nonparen">6 5</span>)</span>
|
||
<span class="paren2">(<span class="nonparen">6 7</span>)</span> <span class="paren2">(<span class="nonparen">6 9</span>)</span> <span class="paren2">(<span class="nonparen">8 1</span>)</span> <span class="paren2">(<span class="nonparen">8 3</span>)</span> <span class="paren2">(<span class="nonparen">8 5</span>)</span> <span class="paren2">(<span class="nonparen">8 7</span>)</span> <span class="paren2">(<span class="nonparen">8 9</span>)</span> <span class="paren2">(<span class="nonparen">10 1</span>)</span> <span class="paren2">(<span class="nonparen">10 3</span>)</span> <span class="paren2">(<span class="nonparen">10 5</span>)</span> <span class="paren2">(<span class="nonparen">10 7</span>)</span> <span class="paren2">(<span class="nonparen">10 9</span>)</span></span>)</span></span></div><p><h2>Implementation</h2><p>The macro <code>collect-list</code> can be constructed using <code>with-collect</code> macro and <a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="hyperspec">LOOP</a> (or <a href="iterate.html" class="category">iterate</a>) macro. Thus it can collect data in the data types which are supported by <a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="hyperspec">LOOP</a> and <a href="Iterate.html" class="category">Iterate</a>. In fact, using <code>with-collect</code> and <code>loop</code> makes the implementation quite easy and straightforward.<p>Here's the implementation of collect-list (based on Loop):<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defmacro.html" class="symbol"><i><span class="symbol">defmacro</span></i></a> collect-list <span class="paren2">(<span class="nonparen">element &body qualifiers</span>)</span>
|
||
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_fletcm_scm_macrolet.html" class="symbol"><i><span class="symbol">labels</span></i></a> <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">build-form <span class="paren5">(<span class="nonparen">qualifiers body</span>)</span>
|
||
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_if.html" class="symbol"><i><span class="symbol">if</span></i></a> <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_not.html" class="symbol">not</a> qualifiers</span>)</span>
|
||
body
|
||
<span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren1">(<span class="nonparen"><span class="paren2">(<span class="nonparen">first-form <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_firstcm_s_inthcm_tenth.html" class="symbol">first</a> qualifiers</span>)</span></span>)</span>
|
||
<span class="paren2">(<span class="nonparen">rest-form <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_rest.html" class="symbol">rest</a> qualifiers</span>)</span></span>)</span></span>)</span>
|
||
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_cond.html" class="symbol"><i><span class="symbol">cond</span></i></a> <span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_stringeqc_ng-not-lessp.html" class="symbol">string-equal</a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_symbol-name.html" class="symbol">symbol-name</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_firstcm_s_inthcm_tenth.html" class="symbol">first</a> first-form</span>)</span></span>)</span>
|
||
<span class="string">"FOR"</span></span>)</span>
|
||
<span class="paren3">(<span class="nonparen">build-for-clause first-form
|
||
<span class="paren4">(<span class="nonparen">build-form rest-form body</span>)</span></span>)</span></span>)</span>
|
||
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_t.html" class="symbol">t</a>
|
||
`<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> ,first-form
|
||
,<span class="paren4">(<span class="nonparen">build-form rest-form body</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
|
||
<span class="paren4">(<span class="nonparen">build-for-clause <span class="paren5">(<span class="nonparen">form body</span>)</span>
|
||
`<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> ,@form
|
||
<a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a> ,body</span>)</span></span>)</span></span>)</span>
|
||
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren4">(<span class="nonparen"><span class="paren5">(<span class="nonparen">collector <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_gensym.html" class="symbol">gensym</a> <span class="string">"COLLECTOR"</span></span>)</span></span>)</span></span>)</span>
|
||
`<span class="paren4">(<span class="nonparen"><i><span class="symbol">with-collect</span></i> <span class="paren5">(<span class="nonparen">,collector</span>)</span>
|
||
,<span class="paren5">(<span class="nonparen">build-form qualifiers
|
||
`<span class="paren6">(<span class="nonparen">,collector ,element</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span></div><p>And the example will be expanded into:<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><i><span class="symbol">WITH-COLLECT</span></i> <span class="paren2">(<span class="nonparen"><span class="keyword">#:COLLECTOR1702</span></span>)</span>
|
||
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">LOOP</span></i></a> FOR X IN TEST <a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">DO</a>
|
||
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">WHEN</a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_evenpcm_oddp.html" class="symbol">EVENP</a> X</span>)</span>
|
||
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">LOOP</span></i></a> FOR Y IN TEST <a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">DO</a>
|
||
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">WHEN</a> <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_evenpcm_oddp.html" class="symbol">ODDP</a> Y</span>)</span> <span class="paren6">(<span class="nonparen"><span class="keyword">#:COLLECTOR1702</span> <span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">LIST</a> X Y</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span></div><p>Which is also very efficient.<p>The <code>with-collect</code> macro can be found in <a href="https://sourceforge.net/p/clocc/hg/ci/default/tree/src/cllib/simple.lisp">CLOCC/CLLIB/simple.lisp</a>.<p><h2> Other Examples </h2><p>
|
||
<div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> permutation <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a></span>)</span>
|
||
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_if.html" class="symbol"><i><span class="symbol">if</span></i></a> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_null.html" class="symbol">null</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a></span>)</span>
|
||
'<span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen"></span>)</span></span>)</span>
|
||
<span class="paren3">(<span class="nonparen">collect-list <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_cons.html" class="symbol">cons</a> x ys</span>)</span>
|
||
<span class="paren4">(<span class="nonparen">for x in <a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a></span>)</span>
|
||
<span class="paren4">(<span class="nonparen">for ys in <span class="paren5">(<span class="nonparen">permutation <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_removecm__elete-if-not.html" class="symbol">remove</a> x <a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span></div><p><h2>Other Implementations</h2>
|
||
For another take on comprehensions see <a href="http://user.it.uu.se/~svenolof/Collect/">List comprehensions for Lisp</a>, an <a href="LGPL.html" class="internal">LGPL</a>'d general collect macro.<p><h2> An afterthought </h2><p>It’ll be handy to use Iterate instead of Loop, in order to take advantage of its flexibility and expressiveness. But some forms like (for y previous x) are something you definitely don’t want to nest. One way to identify that is to construct it as ((for x …) (for y …)).<p><hr>
|
||
<a href="macro example.html" class="category">macro example</a></div></div>
|
||
<div id="footer" class="buttonbar"><ul><li><a href="List Comprehension.html">Current version</a></li>
|
||
<li><a href="https://www.cliki.net/site/history?article=List%20Comprehension">History</a></li>
|
||
<li><a href="https://www.cliki.net/site/backlinks?article=List%20Comprehension">Backlinks</a></li><li><a href="https://www.cliki.net/site/edit-article?title=List%20Comprehension&from-revision=3799786563">Edit</a></li><li><a href="https://www.cliki.net/site/edit-article?create=t">Create</a></li></ul></div>
|
||
</div>
|
||
<div id="header-buttons" class="buttonbar">
|
||
<ul>
|
||
<li><a href="https://www.cliki.net/">Home</a></li>
|
||
<li><a href="https://www.cliki.net/site/recent-changes">Recent Changes</a></li>
|
||
<li><a href="CLiki.html">About</a></li>
|
||
<li><a href="Text Formatting.html">Text Formatting</a></li>
|
||
<li><a href="https://www.cliki.net/site/tools">Tools</a></li>
|
||
</ul>
|
||
<div id="search">
|
||
<form action="https://www.cliki.net/site/search">
|
||
<label for="search_query" class="hidden">Search CLiki</label>
|
||
<input type="text" name="query" id="search_query" value="" />
|
||
<input type="submit" value="search" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<div id="pageheader">
|
||
<div id="header">
|
||
<span id="logo">CLiki</span>
|
||
<span id="slogan">the common lisp wiki</span>
|
||
<div id="login"><form method="post" action="https://www.cliki.net/site/login">
|
||
<label for="login_name" class="hidden">Account name</label>
|
||
<input type="text" name="name" id="login_name" class="login_input" />
|
||
<label for= "login_password" class="hidden">Password</label>
|
||
<input type="password" name="password" id="login_password" class="login_input" />
|
||
<input type="submit" name="login" value="login" id="login_submit" /><br />
|
||
<div id="register"><a href="https://www.cliki.net/site/register">register</a></div>
|
||
<input type="submit" name="reset-pw" value="reset password" id="reset_pw" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</body></html> |