summaryrefslogtreecommitdiff
path: root/manuals/sly/Signals.html
blob: b24283b514f151824eda896f87bf4b6dba499ae0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!-- Copyright (C) 2013, 2014  David Thompson davet@gnu.org

Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".

A copy of the license is also available from the Free Software
Foundation Web site at http://www.gnu.org/licenses/fdl.html.


The document was typeset with
http://www.texinfo.org/ (GNU Texinfo).
 -->
<!-- Created by GNU Texinfo 6.0, http://www.gnu.org/software/texinfo/ -->
<head>
<title>Sly: Signals</title>

<meta name="description" content="Sly: Signals">
<meta name="keywords" content="Sly: Signals">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta charset="UTF-8">
<link href="index.html#Top" rel="start" title="Top">
<link href="Index.html#Index" rel="index" title="Index">
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
<link href="Time.html#Time" rel="up" title="Time">
<link href="Coroutines.html#Coroutines" rel="next" title="Coroutines">
<link href="Time.html#Time" rel="prev" title="Time">
<style type="text/css">
<!--
a.summary-letter {text-decoration: none}
blockquote.indentedblock {margin-right: 0em}
blockquote.smallindentedblock {margin-right: 0em; font-size: smaller}
blockquote.smallquotation {font-size: smaller}
div.display {margin-left: 3.2em}
div.example {margin-left: 3.2em}
div.lisp {margin-left: 3.2em}
div.smalldisplay {margin-left: 3.2em}
div.smallexample {margin-left: 3.2em}
div.smalllisp {margin-left: 3.2em}
kbd {font-style: oblique}
pre.display {font-family: inherit}
pre.format {font-family: inherit}
pre.menu-comment {font-family: serif}
pre.menu-preformatted {font-family: serif}
pre.smalldisplay {font-family: inherit; font-size: smaller}
pre.smallexample {font-size: smaller}
pre.smallformat {font-family: inherit; font-size: smaller}
pre.smalllisp {font-size: smaller}
span.nocodebreak {white-space: nowrap}
span.nolinebreak {white-space: nowrap}
span.roman {font-family: serif; font-weight: normal}
span.sansserif {font-family: sans-serif; font-weight: normal}
ul.no-bullet {list-style: none}
-->
</style>


</head>

<body lang="en">
<a name="Signals"></a>
<div class="header">
<p>
Next: <a href="Coroutines.html#Coroutines" accesskey="n" rel="next">Coroutines</a>, Up: <a href="Time.html#Time" accesskey="u" rel="up">Time</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Index.html#Index" title="Index" rel="index">Index</a>]</p>
</div>
<hr>
<a name="Signals-1"></a>
<h4 class="subsection">4.3.1 Signals</h4>

<div class="example">
<pre class="example">(use-modules (sly signal))
</pre></div>

<p>Game state is a function of time.  The player&rsquo;s score, the current
stage, an enemy&rsquo;s hit points, etc. all change in response to events
that happen at discrete points in time.  Typically, this means that a
number of callback procedures are registered to respond to events
which mutate the relevant data structures.  However, this approach,
while simple and effective, comes at the price of readability,
reproducibility, and expression.  Instead of explicitly mutating data
and entering &ldquo;callback hell&rdquo;, Sly abstracts and formalizes the
process using a functional reactive programming style.
</p>
<p>In Sly, time-varying values are called &ldquo;signals&rdquo;, and they are
defined in a declarative and functional manner.  Rather than
describing the process of mutation procedurally, one describes the
relationships between signals instead.  The result is a &ldquo;signal
graph&rdquo;, a directed acyclic graph of event responses.
</p>
<div class="example">
<pre class="example">(define-signal position
  (signal-fold v+ (vector2 320 240)
               (signal-map (lambda (v) (v* v 4))
                           (signal-sample 1 key-arrows))))
</pre></div>

<p>This signal describes a relationship between the arrow keys on the
keyboard and the position of the player.  <code>signal-sample</code> is used
to trigger a signal update upon every game tick that provides the
current state of the arrow keys.  <code>key-arrows</code> is a 2D vector
that maps to the current state of the arrow keys, allowing for 8
directional movement.  This vector is then scaled 4x to make the
player move faster.  Finally, the scaled vector is added to the
previous player position via <code>signal-fold</code>.  The player&rsquo;s
position is at (320, 240) initially.  As you can see, there are no
callbacks and explicit mutation needed, and the position seems to
magically change with the passage of time.
</p>
<dl>
<dt><a name="index-signal_003f"></a>Scheme Procedure: <strong>signal?</strong> <em><var>obj</var></em></dt>
<dd><p>Return <code>#t</code> if <var>obj</var> is a signal.
</p></dd></dl>

<dl>
<dt><a name="index-make_002dsignal"></a>Scheme Procedure: <strong>make-signal</strong> <em><var>value</var></em></dt>
<dd><p>Wrap <var>value</var> in a signal.
</p></dd></dl>

<dl>
<dt><a name="index-define_002dsignal"></a>Scheme Syntax: <strong>define-signal</strong> <em><var>name</var> <var>value</var></em></dt>
<dd><p>Create a top-level signal variable called <var>name</var>.  If the variable
already exists and refers to a signal then its outputs will be spliced
into the new signal.  If the given value is not a signal then it will
be put into one via <code>make-signal</code>.
</p>
<p><code>define-signal</code> is particularly useful when working at the REPL.
A top-level signal variable defined by <code>define-signal</code> can be
redefined at runtime, and the signals that depended on the old signal
will continue to work with the new signal.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dref"></a>Scheme Procedure: <strong>signal-ref</strong> <em><var>signal</var></em></dt>
<dd><p>Return the value stored within <var>signal</var>.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dref_002dmaybe"></a>Scheme Procedure: <strong>signal-ref-maybe</strong> <em>object</em></dt>
<dd><p>Return the value stored within <var>object</var> if <var>object</var> is a
signal.  Otherwise, return <var>object</var>.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dlet"></a>Scheme Syntax: <strong>signal-let</strong> <em>((<var>var</var> <var>signal</var>) &hellip;) <var>body</var> &hellip;</em></dt>
<dd><p>Evaluate <var>body</var> in the context of the local bindings defined by
the two-element lists <code>((var signal) &hellip;)</code>.
<code>signal-let</code> works like regular <code>let</code>, except that it
derefences <var>signal</var> before binding to <var>var</var>.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dlet_002a"></a>Scheme Syntax: <strong>signal-let*</strong> <em>((<var>var</var> <var>signal</var>) &hellip;) <var>body</var> &hellip;</em></dt>
<dd><p>Similar to <code>signal-let</code>, but the variable bindings are performed
sequentially.  This means that all initialization expressions are
allowed to use the variables defined to the their left in the binding
list.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dset_0021"></a>Scheme Procedure: <strong>signal-set!</strong> <em>signal-box value</em></dt>
<dd><p>Change the contents of <var>signal</var> to <var>value</var>.  This procedure
should almost never be used, except to bootstrap a root node of a
signal graph.
</p></dd></dl>

<dl>
<dt><a name="index-hook_002d_003esignal"></a>Scheme Procedure: <strong>hook-&gt;signal</strong> <em><var>hook</var> <var>init</var> <var>proc</var></em></dt>
<dd><p>Create a new signal whose initial value is <var>init</var> and whose future
values are calculated by applying <var>proc</var> to the arguments passed
when <var>hook</var> is run.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dmerge"></a>Scheme Procedure: <strong>signal-merge</strong> <em><var>signal1</var> <var>signal2</var> . <var>rest</var></em></dt>
<dd><p>Create a new signal whose value is the that of the most recently
updated signal in <var>signal1</var>, <var>signal2</var>, etc.  The initial
value is that of <var>signal1</var>.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dzip"></a>Scheme Procedure: <strong>signal-zip</strong> <em>. <var>signals</var></em></dt>
<dd><p>Create a new signal whose value is a list of the values stored in
<var>signals</var>.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dmap"></a>Scheme Procedure: <strong>signal-map</strong> <em><var>proc</var> <var>signal</var> . <var>rest</var></em></dt>
<dd><p>Create a new signal that applies <var>proc</var> to the values of
<var>SIGNAL</var>.  More than one input signal may be specified, in which
case <var>proc</var> must accept as many arguments as there are input
signals.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dsample_002don"></a>Scheme Procedure: <strong>signal-sample-on</strong> <em><var>value-signal</var> <var>sample-signal</var></em></dt>
<dd><p>Create a new signal that takes on the value of <var>value-signal</var>
whenever <var>sample-signal</var> receives a new value.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dnegate"></a>Scheme Procedure: <strong>signal-negate</strong> <em><var>signal</var></em></dt>
<dd><p>Create a new signal whose value is the negation of <var>signal</var> by
applying <code>not</code> to each value received.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dfold"></a>Scheme Procedure: <strong>signal-fold</strong> <em><var>proc</var> <var>init</var> <var>signal</var> . <var>rest</var></em></dt>
<dd><p>Create a new signal that applies <var>proc</var> with the value received
from <var>signal</var> and the past value of itself, starting with
<var>init</var>.  Like <code>signal-map</code>, more than one input signal may be
given.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dfilter"></a>Scheme Procedure: <strong>signal-filter</strong> <em><var>predicate</var> <var>default</var> <var>signal</var></em></dt>
<dd><p>Create a new signal that takes on the value received from <var>signal</var>
when it satisfies the procedure <var>predicate</var>.  The value of the
signal is <var>default</var> in the case that the predicate is never
satisfied.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002ddrop"></a>Scheme Procedure: <strong>signal-drop</strong> <em><var>predicate</var> <var>default</var> <var>signal</var></em></dt>
<dd><p>Create a new signal that takes on the value received from <var>signal</var>
when it does <em>not</em> satisfy the procedure <var>predicate</var>.  The
value of the signal is <var>default</var> in the case that the predicate is
never satisfied.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002ddrop_002drepeats"></a>Scheme Procedure: <strong>signal-drop-repeats</strong> <em><var>signal</var> [<var>equal?</var>]</em></dt>
<dd><p>Create a new signal that drops the value received from <var>signal</var>
when it is equivalent to the current value.  By default, <code>equal?</code>
is used for testing equivalence.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dswitch"></a>Scheme Procedure: <strong>signal-switch</strong> <em><var>predicate</var> <var>on</var> <var>off</var></em></dt>
<dd><p>Create a new signal whose value is that of the signal <var>on</var> when
the signal <var>predicate</var> is true, or the value of the signal
<var>off</var> otherwise.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dconstant"></a>Scheme Procedure: <strong>signal-constant</strong> <em><var>constant</var> <var>signal</var></em></dt>
<dd><p>Create a new signal whose value is always <var>constant</var> no matter the
value received from <var>signal</var>.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dcount"></a>Scheme Procedure: <strong>signal-count</strong> <em><var>signal</var> [<var>start</var>] [<var>step</var>]</em></dt>
<dd><p>Create a new signal that increments a counter by <var>step</var> when a
value from <var>signal</var> is received, starting from <var>start</var>.  By
default, <var>start</var> is 0 and <var>step</var> is 1.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dtap"></a>Scheme Procedure: <strong>signal-tap</strong> <em><var>proc</var> <var>signal</var></em></dt>
<dd><p>Create a new signal that applies <var>proc</var> for side-effects when a
value from <var>signal</var> is received.  The value of the new signal will
always be the value of <var>signal</var>.  This signal is a convenient way
to sneak in a procedure that with a side-effect into a signal graph.
Such a signal might write text to a file, or play a sound.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dtimestamp"></a>Scheme Procedure: <strong>signal-timestamp</strong> <em><var>signal</var></em></dt>
<dd><p>Create a new signal whose value is a pair, the car of which is the
time that the value of <var>signal</var> was received and the cdr of which
is the received value.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dtime"></a>Scheme Procedure: <strong>signal-time</strong> <em><var>signal</var></em></dt>
<dd><p>Create a new signal whose value is the time that the value of
<var>signal</var> was received.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dsample"></a>Scheme Procedure: <strong>signal-sample</strong> <em><var>step</var> <var>signal</var></em></dt>
<dd><p>Create a new signal that takes on the value of <var>signal</var> every
<var>step</var> ticks.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002devery"></a>Scheme Procedure: <strong>signal-every</strong> <em><var>step</var></em></dt>
<dd><p>Create a new signal that emits <var>step</var> every <var>step</var> ticks.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dsince"></a>Scheme Procedure: <strong>signal-since</strong> <em><var>step</var> <var>signal</var></em></dt>
<dd><p>Create a new signal that emits the time since <var>signal</var> was updated
ever <var>step</var> ticks.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002ddelay"></a>Scheme Procedure: <strong>signal-delay</strong> <em><var>delay</var> <var>signal</var></em></dt>
<dd><p>Create a new signal that delays propagation of <var>signal</var> by
<var>delay</var> ticks..
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dthrottle"></a>Scheme Procedure: <strong>signal-throttle</strong> <em>delay signal</em></dt>
<dd><p>Create a new signal that propagates <var>signal</var> at most once every
<var>delay</var> ticks.
</p></dd></dl>

<dl>
<dt><a name="index-signal_002dgenerator"></a>Scheme Syntax: <strong>signal-generator</strong> <em><var>body</var> &hellip;</em></dt>
<dd><p>Create a new signal whose value is the most recently yielded value of
the coroutine defined by <var>body</var>.  A special <code>yield</code> syntax is
available within <var>body</var> to specify which values are passed to the
signal.
</p></dd></dl>

<hr>
<div class="header">
<p>
Next: <a href="Coroutines.html#Coroutines" accesskey="n" rel="next">Coroutines</a>, Up: <a href="Time.html#Time" accesskey="u" rel="up">Time</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Index.html#Index" title="Index" rel="index">Index</a>]</p>
</div>



</body>
</html>