1
0
Fork 0
cl-sites/guile.html_node/Control-Flow.html

194 lines
9.8 KiB
HTML
Raw Normal View History

2024-12-17 12:49:28 +01:00
<!DOCTYPE html>
<html>
<!-- Created by GNU Texinfo 7.1, https://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!-- This manual documents Guile version 3.0.10.
Copyright (C) 1996-1997, 2000-2005, 2009-2023 Free Software Foundation,
Inc.
Copyright (C) 2021 Maxime Devos
Copyright (C) 2024 Tomas Volf
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." -->
<title>Control Flow (Guile Reference Manual)</title>
<meta name="description" content="Control Flow (Guile Reference Manual)">
<meta name="keywords" content="Control Flow (Guile Reference Manual)">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content=".texi2any-real">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="index.html" rel="start" title="Top">
<link href="Concept-Index.html" rel="index" title="Concept Index">
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
<link href="General-Libguile-Concepts.html" rel="up" title="General Libguile Concepts">
<link href="Asynchronous-Signals.html" rel="next" title="Asynchronous Signals">
<link href="Garbage-Collection.html" rel="prev" title="Garbage Collection">
<style type="text/css">
<!--
a.copiable-link {visibility: hidden; text-decoration: none; line-height: 0em}
div.example {margin-left: 3.2em}
span:hover a.copiable-link {visibility: visible}
-->
</style>
<link rel="stylesheet" type="text/css" href="https://www.gnu.org/software/gnulib/manual.css">
</head>
<body lang="en">
<div class="subsection-level-extent" id="Control-Flow">
<div class="nav-panel">
<p>
Next: <a href="Asynchronous-Signals.html" accesskey="n" rel="next">Asynchronous Signals</a>, Previous: <a href="Garbage-Collection.html" accesskey="p" rel="prev">Garbage Collection</a>, Up: <a href="General-Libguile-Concepts.html" accesskey="u" rel="up">General concepts for using libguile</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
</div>
<hr>
<h4 class="subsection" id="Control-Flow-1"><span>5.4.3 Control Flow<a class="copiable-link" href="#Control-Flow-1"> &para;</a></span></h4>
<p>Scheme has a more general view of program flow than C, both locally and
non-locally.
</p>
<p>Controlling the local flow of control involves things like gotos, loops,
calling functions and returning from them. Non-local control flow
refers to situations where the program jumps across one or more levels
of function activations without using the normal call or return
operations.
</p>
<p>The primitive means of C for local control flow is the <code class="code">goto</code>
statement, together with <code class="code">if</code>. Loops done with <code class="code">for</code>,
<code class="code">while</code> or <code class="code">do</code> could in principle be rewritten with just
<code class="code">goto</code> and <code class="code">if</code>. In Scheme, the primitive means for local
control flow is the <em class="emph">function call</em> (together with <code class="code">if</code>).
Thus, the repetition of some computation in a loop is ultimately
implemented by a function that calls itself, that is, by recursion.
</p>
<p>This approach is theoretically very powerful since it is easier to
reason formally about recursion than about gotos. In C, using
recursion exclusively would not be practical, though, since it would eat
up the stack very quickly. In Scheme, however, it is practical:
function calls that appear in a <em class="dfn">tail position</em> do not use any
additional stack space (see <a class="pxref" href="Tail-Calls.html">Tail calls</a>).
</p>
<p>A function call is in a tail position when it is the last thing the
calling function does. The value returned by the called function is
immediately returned from the calling function. In the following
example, the call to <code class="code">bar-1</code> is in a tail position, while the
call to <code class="code">bar-2</code> is not. (The call to <code class="code">1-</code> in <code class="code">foo-2</code>
is in a tail position, though.)
</p>
<div class="example lisp">
<pre class="lisp-preformatted">(define (foo-1 x)
(bar-1 (1- x)))
(define (foo-2 x)
(1- (bar-2 x)))
</pre></div>
<p>Thus, when you take care to recurse only in tail positions, the
recursion will only use constant stack space and will be as good as a
loop constructed from gotos.
</p>
<p>Scheme offers a few syntactic abstractions (<code class="code">do</code> and <em class="dfn">named</em>
<code class="code">let</code>) that make writing loops slightly easier.
</p>
<p>But only Scheme functions can call other functions in a tail position:
C functions can not. This matters when you have, say, two functions
that call each other recursively to form a common loop. The following
(unrealistic) example shows how one might go about determining whether a
non-negative integer <var class="var">n</var> is even or odd.
</p>
<div class="example lisp">
<pre class="lisp-preformatted">(define (my-even? n)
(cond ((zero? n) #t)
(else (my-odd? (1- n)))))
(define (my-odd? n)
(cond ((zero? n) #f)
(else (my-even? (1- n)))))
</pre></div>
<p>Because the calls to <code class="code">my-even?</code> and <code class="code">my-odd?</code> are in tail
positions, these two procedures can be applied to arbitrary large
integers without overflowing the stack. (They will still take a lot
of time, of course.)
</p>
<p>However, when one or both of the two procedures would be rewritten in
C, it could no longer call its companion in a tail position (since C
does not have this concept). You might need to take this
consideration into account when deciding which parts of your program
to write in Scheme and which in C.
</p>
<p>In addition to calling functions and returning from them, a Scheme
program can also exit non-locally from a function so that the control
flow returns directly to an outer level. This means that some functions
might not return at all.
</p>
<p>Even more, it is not only possible to jump to some outer level of
control, a Scheme program can also jump back into the middle of a
function that has already exited. This might cause some functions to
return more than once.
</p>
<p>In general, these non-local jumps are done by invoking
<em class="dfn">continuations</em> that have previously been captured using
<code class="code">call-with-current-continuation</code>. Guile also offers a slightly
restricted set of functions, <code class="code">catch</code> and <code class="code">throw</code>, that can
only be used for non-local exits. This restriction makes them more
efficient. Error reporting (with the function <code class="code">error</code>) is
implemented by invoking <code class="code">throw</code>, for example. The functions
<code class="code">catch</code> and <code class="code">throw</code> belong to the topic of <em class="dfn">exceptions</em>.
</p>
<p>Since Scheme functions can call C functions and vice versa, C code can
experience the more general control flow of Scheme as well. It is
possible that a C function will not return at all, or will return more
than once. While C does offer <code class="code">setjmp</code> and <code class="code">longjmp</code> for
non-local exits, it is still an unusual thing for C code. In
contrast, non-local exits are very common in Scheme, mostly to report
errors.
</p>
<p>You need to be prepared for the non-local jumps in the control flow
whenever you use a function from <code class="code">libguile</code>: it is best to assume
that any <code class="code">libguile</code> function might signal an error or run a pending
signal handler (which in turn can do arbitrary things).
</p>
<p>It is often necessary to take cleanup actions when the control leaves a
function non-locally. Also, when the control returns non-locally, some
setup actions might be called for. For example, the Scheme function
<code class="code">with-output-to-port</code> needs to modify the global state so that
<code class="code">current-output-port</code> returns the port passed to
<code class="code">with-output-to-port</code>. The global output port needs to be reset to
its previous value when <code class="code">with-output-to-port</code> returns normally or
when it is exited non-locally. Likewise, the port needs to be set again
when control enters non-locally.
</p>
<p>Scheme code can use the <code class="code">dynamic-wind</code> function to arrange for
the setting and resetting of the global state. C code can use the
corresponding <code class="code">scm_internal_dynamic_wind</code> function, or a
<code class="code">scm_dynwind_begin</code>/<code class="code">scm_dynwind_end</code> pair together with
suitable &rsquo;dynwind actions&rsquo; (see <a class="pxref" href="Dynamic-Wind.html">Dynamic Wind</a>).
</p>
<p>Instead of coping with non-local control flow, you can also prevent it
by erecting a <em class="emph">continuation barrier</em>, See <a class="xref" href="Continuation-Barriers.html">Continuation Barriers</a>. The function <code class="code">scm_c_with_continuation_barrier</code>, for
example, is guaranteed to return exactly once.
</p>
</div>
<hr>
<div class="nav-panel">
<p>
Next: <a href="Asynchronous-Signals.html">Asynchronous Signals</a>, Previous: <a href="Garbage-Collection.html">Garbage Collection</a>, Up: <a href="General-Libguile-Concepts.html">General concepts for using libguile</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
</div>
</body>
</html>