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

125 lines
No EOL
13 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>CLiki: cells</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=cells">
<link rel="stylesheet" href="static/css/style.css">
<link rel="stylesheet" href="static/css/colorize.css">
</head>
<body>
<span class="hidden">CLiki - cells</span>
<div id="content"><div id="content-area"><div id="article-title">cells</div><div id="article"><a href="cells.html" class="internal">cells</a> is a <a href="dataflow.html" class="category">dataflow</a> extension to CLOS (think spreadsheet-type programming, with slots being spreadsheet cells) by <a href="Kenny&#32;Tilton.html" class="internal">Kenny Tilton</a>. It is released under a MIT-type license. Its <a href="http://www.common-lisp.net/project/cells/">home page</a> is at common-lisp.net. It has undergone a major revision since it was first publicly released, and now has a significantly improved data-propagation model. On Kenny's Cells webpage, the citation for Bill Clementson's blog about Cells is valid, but Cells syntax changes have rendered the example inoperative. <em>Updated example <a href="https://gitlab.common-lisp.net/cells/cells/blob/master/doc/motor-control.lisp">here</a></em><p>Currently supported implementations are Allegro CL, SBCL, LispWorks, CLISP, ECL, ABCL, CCL and OpenMCL. It suffers from what appears to be a bug in CMUCL's CLOS implementation, so is only partially supported there. In the past it has worked on Corman Lisp and MCL, and resurrecting this support is most likely trivial.<p>Find the current version and access to the mailing-list on common-lisp.net, the source via gitlab <a href="https://gitlab.common-lisp.net/cells/cells">here</a> [doesn't seem to be up-to-date]. Development occurs <a href="https://github.com/kennytilton/cells">here</a>.<p>There is a git repository with a collection of small fixes <a href="http://github.com/Ramarren/cells/tree/master">on github</a> (for those who don't want to bother with git there is an <a href="http://github.com/Ramarren/cells/tarball/master">automatically generated tarball</a>). -- Little outdated, but supports more implementations.<p>There is an attempt at documentation available <a href="http://github.com/stefano/cells-doc/tree/master">on github</a> (<a href="http://github.com/stefano/cells-doc/tarball/master">tarball</a>).<p><h2>Notes</h2><p><h4>Understanding Cells</h4><p>After trying it out a bit, my understanding is this: You can define objects whose slots trigger events when their values are modified. These slots are called "cells."<p>I think that's it; the rest is detail.<p>Two kinds of things happen when a cell's value is changed:<p><ul>
<li>
<h5>Dependencies updated</h5><p>You can specify that <tt>cell-1</tt>'s value depends on <tt>cell-2</tt>. If <tt>cell-2</tt> is changed, <tt>cell-1</tt> will be updated.<p></li>
<li>
<h5>Observer functions run</h5><p>You can write observer functions which are called when a cell of a given name is updated. I think only the Cells system can call them directly. (Which implies you're using them just for side-effects.)<p><i>(Hmm, does this scale? You can make 100 objects, but each of their cells {<tt>cell-1</tt>..<tt>cell-N</tt>} will have to share observers named {<tt>cell-1</tt>..<tt>cell-N</tt>}.)</i>
</li>
</ul>
<b>Basic example:</b><p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><i><span class="symbol">defmodel</span></i> my-cell <span class="paren2">(<span class="nonparen"></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">cell-1 <span class="keyword">:cell</span> <a href="https://www.cliki.net/site/HyperSpec/Body/any_t.html" class="symbol">t</a>
<span class="keyword">:initform</span> <span class="paren4">(<span class="nonparen">c-in 1</span>)</span> <span class="comment">; c-in allows you to to modify this cell, with (for example) setf
</span> <span class="keyword">:accessor</span> cell-1</span>)</span>
<span class="paren3">(<span class="nonparen">cell-2 <span class="keyword">:cell</span> <a href="https://www.cliki.net/site/HyperSpec/Body/any_t.html" class="symbol">t</a>
<span class="keyword">:initform</span> <span class="paren4">(<span class="nonparen">c? <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_st.html" class="symbol">*</a> <span class="paren6">(<span class="nonparen">^cell-1</span>)</span> 2</span>)</span></span>)</span> <span class="comment">; c? bars you from modifying this cell, signalling an error; it only changes when cell-1 does
</span> <span class="keyword">:accessor</span> cell-2</span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defparametercm_defvar.html" class="symbol"><i><span class="symbol">defparameter</span></i></a> <span class="special">*cell*</span> <span class="paren2">(<span class="nonparen">make-be 'my-cell</span>)</span></span>)</span></span></div><p><tt>Cell-2</tt> depends on <tt>cell-1</tt>'s value. If <tt>cell-1</tt> were to change, <tt>cell-2</tt>'s value would change to be twice <tt>cell-1</tt>. So, let's try it out:<p><pre>
CL-USER&gt; (cell-1 *cell*)
1
CL-USER&gt; (cell-2 *cell*)
2
CL-USER&gt; (setf (cell-1 *cell*) 10)
10
CL-USER&gt; (cell-1 *cell*)
10
CL-USER&gt; (cell-2 *cell*)
20
</pre><p>We can see that the syntax diverges a little from normal CLOS:<p><ul>
<li>
<tt>defclass</tt><tt>defmodel</tt> <i>(Reasoning—syntactic sugar will be bound which normal CLOS can't accomodate.)</i>
</li>
<li>
<tt>make-instance</tt><tt>make-be</tt>
</li>
<li>There's a <tt>:cell</tt> slot option.
</li>
<li>Slots are initialized with <tt>(c-in ...)</tt> and <tt>(c? ...)</tt> forms.
</li>
<li>You can refer to other cells by calling the (^<i>cell-N</i>) function (where <i>cell-N</i> is the name of another cell in the class)
</li>
</ul>
<i>[todo: discuss observers]</i><p><h4>State vs. events</h4><p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><i><span class="symbol">defmodel</span></i> my-model <span class="paren2">(<span class="nonparen"></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">cell-1 <span class="keyword">:cell</span> <a href="https://www.cliki.net/site/HyperSpec/Body/any_t.html" class="symbol">t</a> ...</span>)</span>
<span class="paren3">(<span class="nonparen">cell-2 <span class="keyword">:cell</span> <span class="keyword">:ephemeral</span> ...</span>)</span></span>)</span></span>)</span></span></div><p><tt>cell-1</tt> will keep its new value when changed.<p><tt>cell-2</tt>, however, will revert instantly to whatever it was initialized with, after dependencies/observers on <tt>cell-2</tt> are triggered.<p><i>(Philosophical background: From my (nonexpert) understanding, discrete processes are categorized into states and events, corresponding to <tt>:cell t</tt> and <tt>:cell :ephemeral</tt>, respectively. This is taken from Sowa's <a href="http://www.jfsowa.com/krbook/">knowledge representation book</a>.)</i><p><i>(The docs mention :delta, but seems unsupported.)</i><p><h4>How one cell depends on another</h4><p>Cell-1 depends on cell-2 if (and only if) cell-1 looked at cell-2 <b>the last time cell-1's <tt>c?</tt> code ran</b>. Kenny Tilton <a href="http://groups.google.com/group/comp.lang.lisp/msg/ba3d08f6fa9ddcb1?hl=en">explained on usenet</a>:<p><blockquote>
<i>So dependencies will vary after every invocation of, say:</i><p></blockquote><div class="code"><span class="nonparen"> <span class="paren1">(<span class="nonparen">c? <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</span>)</span><span class="paren3">(<span class="nonparen">^b</span>)</span><span class="paren3">(<span class="nonparen">^c</span>)</span></span>)</span></span>)</span></span></div><p><i>between A and B or A and C.</i><p><i>Interestingly, this means inelegant code can create problems:</i><p><div class="code"><span class="nonparen"> <span class="paren1">(<span class="nonparen">c? <span class="paren2">(<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="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">b <span class="paren5">(<span class="nonparen">^b</span>)</span></span>)</span><span class="paren4">(<span class="nonparen">c <span class="paren5">(<span class="nonparen">^c</span>)</span></span>)</span></span>)</span>
<span class="paren3">(<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="paren4">(<span class="nonparen">^a</span>)</span> b c</span>)</span></span>)</span></span>)</span></span></div><p><i>...always produces dependencies A, B, and C, which is a lie.</i><p><i>Note, btw, that dependencies are dynamic, not lexical: call a function that accesses a cell and you still get a dependency.</i><p><h4>Special names</h4><p>From Kenny Tilton's <a href="http://groups.google.com/group/comp.lang.lisp/msg/479e96de3f082ea6?hl=en">post</a>:<p><ul>
<li>
<tt>(^slotname)</tt> - within a <tt>c?</tt> or <tt>def-c-output</tt> form, holds the current value of that slot
</li>
<li>
<tt>self</tt> - (look into this. only know it's bound by default within a def-c-output form to the current instance)
</li>
<li>
<tt>.cache</tt> - within a <tt>c?</tt> form, holds the current value of a cell
</li>
<li>
<tt>.parent</tt> - <i>[todo, dunno what it does]</i>
</li>
<li>
<tt>.cause</tt> - <i>symbol-macro of some sort, I don't suggest you use this as it seems unsupported</i>
</li>
</ul>
<h4>Recovering from c-stop</h4><p>Call <tt>(cell-reset)</tt> if <tt>c-stop</tt> is invoked. <tt>c-stop</tt> apparently halts the Cells system when circular dependencies are detected, and maybe other scenarios too.<p>An error message like the following may occur (formatted to be more readable):<p><pre>
0&gt; c-calculate-and-set breaking on circularity | [?#:&lt;vld&gt;=[236]LOCATION/#&lt;COMPUTER {41094259}&gt;]
C-STOP&gt; stopping because (cell ~a midst askers: ~a
[?#:&lt;vld&gt;=[236]LOCATION/#&lt;COMPUTER {41094259}&gt;]
([?#:&lt;vld&gt;=[236]RESPONSE/#&lt;COMPUTER {41094259}&gt;]
[?#:&lt;vld&gt;=[236]LOCATION/#&lt;COMPUTER {41094259}&gt;]))
c-break &gt; stopping &gt; (cell ~a midst askers: ~a
[?#:&lt;vld&gt;=[236]LOCATION/#&lt;COMPUTER {41094259}&gt;]
([?#:&lt;vld&gt;=[236]RESPONSE/#&lt;COMPUTER {41094259}&gt;]
[?#:&lt;vld&gt;=[236]LOCATION/#&lt;COMPUTER {41094259}&gt;]))
</pre><p>So we execute:<p><pre>
CL-USER&gt; (cell-reset)
NIL
</pre></div></div>
<div id="footer" class="buttonbar"><ul><li><a href="cells.html">Current version</a></li>
<li><a href="https://www.cliki.net/site/history?article=cells">History</a></li>
<li><a href="https://www.cliki.net/site/backlinks?article=cells">Backlinks</a></li><li><a href="https://www.cliki.net/site/edit-article?title=cells&amp;from-revision=3770347347">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>