emacs.d/clones/lisp/www.cliki.net/List comprehension.html
2022-10-07 15:47:14 +02:00

89 lines
No EOL
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 &amp;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>Itll 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 dont want to nest. One way to identify that is to construct it as ((for x …) (for y …)).<p><hr>
<a href="macro&#32;example.html" class="category">macro example</a></div></div>
<div id="footer" class="buttonbar"><ul><li><a href="List&#32;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&amp;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&#32;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>