code.html 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  3. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  4. <html xmlns="http://www.w3.org/1999/xhtml" lang="English" xml:lang="English">
  5. <head>
  6. <!-- 2023-11-26 Sun 11:55 -->
  7. <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  8. <meta name="viewport" content="width=device-width, initial-scale=1" />
  9. <title>The Seasoned Schemer Notes</title>
  10. <meta name="author" content="Zelphir Kaltstahl" />
  11. <meta name="generator" content="Org Mode" />
  12. <style>
  13. #content { max-width: 60em; margin: auto; }
  14. .title { text-align: center;
  15. margin-bottom: .2em; }
  16. .subtitle { text-align: center;
  17. font-size: medium;
  18. font-weight: bold;
  19. margin-top:0; }
  20. .todo { font-family: monospace; color: red; }
  21. .done { font-family: monospace; color: green; }
  22. .priority { font-family: monospace; color: orange; }
  23. .tag { background-color: #eee; font-family: monospace;
  24. padding: 2px; font-size: 80%; font-weight: normal; }
  25. .timestamp { color: #bebebe; }
  26. .timestamp-kwd { color: #5f9ea0; }
  27. .org-right { margin-left: auto; margin-right: 0px; text-align: right; }
  28. .org-left { margin-left: 0px; margin-right: auto; text-align: left; }
  29. .org-center { margin-left: auto; margin-right: auto; text-align: center; }
  30. .underline { text-decoration: underline; }
  31. #postamble p, #preamble p { font-size: 90%; margin: .2em; }
  32. p.verse { margin-left: 3%; }
  33. pre {
  34. border: 1px solid #e6e6e6;
  35. border-radius: 3px;
  36. background-color: #f2f2f2;
  37. padding: 8pt;
  38. font-family: monospace;
  39. overflow: auto;
  40. margin: 1.2em;
  41. }
  42. pre.src {
  43. position: relative;
  44. overflow: auto;
  45. }
  46. pre.src:before {
  47. display: none;
  48. position: absolute;
  49. top: -8px;
  50. right: 12px;
  51. padding: 3px;
  52. color: #555;
  53. background-color: #f2f2f299;
  54. }
  55. pre.src:hover:before { display: inline; margin-top: 14px;}
  56. /* Languages per Org manual */
  57. pre.src-asymptote:before { content: 'Asymptote'; }
  58. pre.src-awk:before { content: 'Awk'; }
  59. pre.src-authinfo::before { content: 'Authinfo'; }
  60. pre.src-C:before { content: 'C'; }
  61. /* pre.src-C++ doesn't work in CSS */
  62. pre.src-clojure:before { content: 'Clojure'; }
  63. pre.src-css:before { content: 'CSS'; }
  64. pre.src-D:before { content: 'D'; }
  65. pre.src-ditaa:before { content: 'ditaa'; }
  66. pre.src-dot:before { content: 'Graphviz'; }
  67. pre.src-calc:before { content: 'Emacs Calc'; }
  68. pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
  69. pre.src-fortran:before { content: 'Fortran'; }
  70. pre.src-gnuplot:before { content: 'gnuplot'; }
  71. pre.src-haskell:before { content: 'Haskell'; }
  72. pre.src-hledger:before { content: 'hledger'; }
  73. pre.src-java:before { content: 'Java'; }
  74. pre.src-js:before { content: 'Javascript'; }
  75. pre.src-latex:before { content: 'LaTeX'; }
  76. pre.src-ledger:before { content: 'Ledger'; }
  77. pre.src-lisp:before { content: 'Lisp'; }
  78. pre.src-lilypond:before { content: 'Lilypond'; }
  79. pre.src-lua:before { content: 'Lua'; }
  80. pre.src-matlab:before { content: 'MATLAB'; }
  81. pre.src-mscgen:before { content: 'Mscgen'; }
  82. pre.src-ocaml:before { content: 'Objective Caml'; }
  83. pre.src-octave:before { content: 'Octave'; }
  84. pre.src-org:before { content: 'Org mode'; }
  85. pre.src-oz:before { content: 'OZ'; }
  86. pre.src-plantuml:before { content: 'Plantuml'; }
  87. pre.src-processing:before { content: 'Processing.js'; }
  88. pre.src-python:before { content: 'Python'; }
  89. pre.src-R:before { content: 'R'; }
  90. pre.src-ruby:before { content: 'Ruby'; }
  91. pre.src-sass:before { content: 'Sass'; }
  92. pre.src-scheme:before { content: 'Scheme'; }
  93. pre.src-screen:before { content: 'Gnu Screen'; }
  94. pre.src-sed:before { content: 'Sed'; }
  95. pre.src-sh:before { content: 'shell'; }
  96. pre.src-sql:before { content: 'SQL'; }
  97. pre.src-sqlite:before { content: 'SQLite'; }
  98. /* additional languages in org.el's org-babel-load-languages alist */
  99. pre.src-forth:before { content: 'Forth'; }
  100. pre.src-io:before { content: 'IO'; }
  101. pre.src-J:before { content: 'J'; }
  102. pre.src-makefile:before { content: 'Makefile'; }
  103. pre.src-maxima:before { content: 'Maxima'; }
  104. pre.src-perl:before { content: 'Perl'; }
  105. pre.src-picolisp:before { content: 'Pico Lisp'; }
  106. pre.src-scala:before { content: 'Scala'; }
  107. pre.src-shell:before { content: 'Shell Script'; }
  108. pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
  109. /* additional language identifiers per "defun org-babel-execute"
  110. in ob-*.el */
  111. pre.src-cpp:before { content: 'C++'; }
  112. pre.src-abc:before { content: 'ABC'; }
  113. pre.src-coq:before { content: 'Coq'; }
  114. pre.src-groovy:before { content: 'Groovy'; }
  115. /* additional language identifiers from org-babel-shell-names in
  116. ob-shell.el: ob-shell is the only babel language using a lambda to put
  117. the execution function name together. */
  118. pre.src-bash:before { content: 'bash'; }
  119. pre.src-csh:before { content: 'csh'; }
  120. pre.src-ash:before { content: 'ash'; }
  121. pre.src-dash:before { content: 'dash'; }
  122. pre.src-ksh:before { content: 'ksh'; }
  123. pre.src-mksh:before { content: 'mksh'; }
  124. pre.src-posh:before { content: 'posh'; }
  125. /* Additional Emacs modes also supported by the LaTeX listings package */
  126. pre.src-ada:before { content: 'Ada'; }
  127. pre.src-asm:before { content: 'Assembler'; }
  128. pre.src-caml:before { content: 'Caml'; }
  129. pre.src-delphi:before { content: 'Delphi'; }
  130. pre.src-html:before { content: 'HTML'; }
  131. pre.src-idl:before { content: 'IDL'; }
  132. pre.src-mercury:before { content: 'Mercury'; }
  133. pre.src-metapost:before { content: 'MetaPost'; }
  134. pre.src-modula-2:before { content: 'Modula-2'; }
  135. pre.src-pascal:before { content: 'Pascal'; }
  136. pre.src-ps:before { content: 'PostScript'; }
  137. pre.src-prolog:before { content: 'Prolog'; }
  138. pre.src-simula:before { content: 'Simula'; }
  139. pre.src-tcl:before { content: 'tcl'; }
  140. pre.src-tex:before { content: 'TeX'; }
  141. pre.src-plain-tex:before { content: 'Plain TeX'; }
  142. pre.src-verilog:before { content: 'Verilog'; }
  143. pre.src-vhdl:before { content: 'VHDL'; }
  144. pre.src-xml:before { content: 'XML'; }
  145. pre.src-nxml:before { content: 'XML'; }
  146. /* add a generic configuration mode; LaTeX export needs an additional
  147. (add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */
  148. pre.src-conf:before { content: 'Configuration File'; }
  149. table { border-collapse:collapse; }
  150. caption.t-above { caption-side: top; }
  151. caption.t-bottom { caption-side: bottom; }
  152. td, th { vertical-align:top; }
  153. th.org-right { text-align: center; }
  154. th.org-left { text-align: center; }
  155. th.org-center { text-align: center; }
  156. td.org-right { text-align: right; }
  157. td.org-left { text-align: left; }
  158. td.org-center { text-align: center; }
  159. dt { font-weight: bold; }
  160. .footpara { display: inline; }
  161. .footdef { margin-bottom: 1em; }
  162. .figure { padding: 1em; }
  163. .figure p { text-align: center; }
  164. .equation-container {
  165. display: table;
  166. text-align: center;
  167. width: 100%;
  168. }
  169. .equation {
  170. vertical-align: middle;
  171. }
  172. .equation-label {
  173. display: table-cell;
  174. text-align: right;
  175. vertical-align: middle;
  176. }
  177. .inlinetask {
  178. padding: 10px;
  179. border: 2px solid gray;
  180. margin: 10px;
  181. background: #ffffcc;
  182. }
  183. #org-div-home-and-up
  184. { text-align: right; font-size: 70%; white-space: nowrap; }
  185. textarea { overflow-x: auto; }
  186. .linenr { font-size: smaller }
  187. .code-highlighted { background-color: #ffff00; }
  188. .org-info-js_info-navigation { border-style: none; }
  189. #org-info-js_console-label
  190. { font-size: 10px; font-weight: bold; white-space: nowrap; }
  191. .org-info-js_search-highlight
  192. { background-color: #ffff00; color: #000000; font-weight: bold; }
  193. .org-svg { }
  194. </style>
  195. </head>
  196. <body>
  197. <div id="content" class="content">
  198. <h1 class="title">The Seasoned Schemer Notes
  199. <br />
  200. <span class="subtitle">Chapter 14</span>
  201. </h1>
  202. <div id="table-of-contents" role="doc-toc">
  203. <h2>Table of Contents</h2>
  204. <div id="text-table-of-contents" role="doc-toc">
  205. <ul>
  206. <li><a href="#prerequisites">1. Prerequisites</a></li>
  207. <li><a href="#chapter-14">2. Chapter 14</a>
  208. <ul>
  209. <li><a href="#chapter-14-attempt-leftmost">2.1. Attempt to write <code class="src src-scheme">leftmost</code></a></li>
  210. <li><a href="#chapter-14-attempt-rember-1-asterisk">2.2. Attempt to write <code class="src src-scheme">rember1*</code></a></li>
  211. <li><a href="#chapter-14-avoid-conditionals">2.3. Using continuations to avoid conditionals</a></li>
  212. <li><a href="#chapter-14-continuations-needed">2.4. When are continuations "needed"?</a>
  213. <ul>
  214. <li><a href="#chapter-14-continuations-needed-success-of-recursive-calls">2.4.1. Unknown success for recursive calls</a></li>
  215. </ul>
  216. </li>
  217. <li><a href="#chapter-14-continuations-for-control-flow">2.5. Using continuations to build other control flow forms</a></li>
  218. </ul>
  219. </li>
  220. </ul>
  221. </div>
  222. </div>
  223. <div id="outline-container-prerequisites" class="outline-2">
  224. <h2 id="prerequisites"><span class="section-number-2">1.</span> Prerequisites</h2>
  225. <div class="outline-text-2" id="text-prerequisites">
  226. <p>
  227. <code class="src src-scheme">atom?</code> checks, whether a thing is a non-compound thing, at least for simple code, that does not make use of vector and such things.
  228. </p>
  229. <div class="org-src-container">
  230. <pre class="src src-scheme" id="org218a286">(define atom?
  231. (λ (x)
  232. (and (not (pair? x))
  233. (not (null? x)))))
  234. </pre>
  235. </div>
  236. </div>
  237. </div>
  238. <div id="outline-container-chapter-14" class="outline-2">
  239. <h2 id="chapter-14"><span class="section-number-2">2.</span> Chapter 14</h2>
  240. <div class="outline-text-2" id="text-chapter-14">
  241. <ul class="org-ul">
  242. <li>This chapter introduces <code class="src src-scheme">if</code>.</li>
  243. <li>This chapter introduces <code class="src src-scheme">letcc</code> and <code class="src src-scheme">call-with-current-continuation</code>.</li>
  244. <li>This chapter introduces <code class="src src-scheme">try</code>.</li>
  245. <li>This chapter shows more ways of making use of continuations for various purposes.</li>
  246. </ul>
  247. </div>
  248. <div id="outline-container-chapter-14-attempt-leftmost" class="outline-3">
  249. <h3 id="chapter-14-attempt-leftmost"><span class="section-number-3">2.1.</span> Attempt to write <code class="src src-scheme">leftmost</code></h3>
  250. <div class="outline-text-3" id="text-chapter-14-attempt-leftmost">
  251. <p>
  252. <code class="src src-scheme">leftmost</code> returns the leftmost atom of a nested list or tree.
  253. </p>
  254. <div class="org-src-container">
  255. <pre class="src src-scheme" id="orgdfd105b">
  256. (define leftmost
  257. (λ (lst)
  258. (cond
  259. [(null? lst) '()]
  260. [(atom? (car lst))
  261. (car lst)]
  262. ;; We know car of lst is not an atom and it is not null?, so
  263. ;; it must be at least a pair. We have to try to find the
  264. ;; leftmost element in that pair.
  265. [else
  266. (leftmost (car lst))])))
  267. </pre>
  268. </div>
  269. <div class="org-src-container">
  270. <pre class="src src-scheme" id="orgce4c83f">
  271. (simple-format #t "~a\n" (leftmost '(((() c) (a) (d) b) e)))
  272. </pre>
  273. </div>
  274. <pre class="example" id="org723727f">
  275. ()
  276. </pre>
  277. <p>
  278. But this is not correct. The leftmost element should be <code class="src src-scheme">'c</code>. Maybe we can try to find the leftmost element in the <code class="src src-scheme">car</code> of <code class="src src-scheme">lst</code> and if we do not find it, search in the <code class="src src-scheme">cdr</code> of <code class="src src-scheme">lst</code>:
  279. </p>
  280. <div class="org-src-container">
  281. <pre class="src src-scheme" id="org09859b6">
  282. (define leftmost
  283. (λ (lst)
  284. (cond
  285. [(null? lst) '()]
  286. [(atom? (car lst))
  287. (car lst)]
  288. [else
  289. (let ([leftmost-of-car (leftmost (car lst))])
  290. (cond
  291. [(null? leftmost-of-car) (leftmost (cdr lst))]
  292. [else leftmost-of-car]))])))
  293. </pre>
  294. </div>
  295. <div class="org-src-container">
  296. <pre class="src src-scheme" id="org48e188c">
  297. (simple-format #t "~a\n" (leftmost '(((() c) (a) (d) b) e)))
  298. (simple-format #t "~a\n" (leftmost '((((f) c) (a) (d) b) e)))
  299. </pre>
  300. </div>
  301. <pre class="example" id="org2fbff11">
  302. c
  303. f
  304. </pre>
  305. <p>
  306. This seems to work. No continuations needed so far.
  307. </p>
  308. <p>
  309. The book has a slightly better solution, which asks <code class="src src-scheme">atom?</code> instead of <code class="src src-scheme">null?</code> about the <code class="src src-scheme">leftmost</code> of the <code class="src src-scheme">car</code> of a list. This is clearer, since we are actually interested in getting the <code class="src src-scheme">leftmost</code> atom, and not the <code class="src src-scheme">leftmost</code> <code class="src src-scheme">null?</code> and as such do not need to invert the thinking. My solution also works, but only because it has the convention of returning <code class="src src-scheme">'()</code> when <code class="src src-scheme">(null? lst)</code> is <code class="src src-scheme">#t</code>. The book's solution does not rely on the returned thing being exactly <code class="src src-scheme">'()</code>, so it has fewer conventions backed in and is more flexible than my solution.
  310. </p>
  311. </div>
  312. </div>
  313. <div id="outline-container-chapter-14-attempt-rember-1-asterisk" class="outline-3">
  314. <h3 id="chapter-14-attempt-rember-1-asterisk"><span class="section-number-3">2.2.</span> Attempt to write <code class="src src-scheme">rember1*</code></h3>
  315. <div class="outline-text-3" id="text-chapter-14-attempt-rember-1-asterisk">
  316. <p>
  317. <code class="src src-scheme">rember1*</code> removes the leftmost occurrence of an element satisfying a predicate from an arbitrarily nested list. The version in the book works with atoms. My version here should work even with compound values.
  318. </p>
  319. <div class="org-src-container">
  320. <pre class="src src-scheme" id="org79a14e9">(import (srfi srfi-11))
  321. (define rember1*
  322. (λ (lst pred)
  323. (letrec ([rember-inner
  324. (λ (lst)
  325. (cond
  326. [(null? lst) (values #f '())]
  327. [(pred (car lst)) (values #t (cdr lst))]
  328. [(atom? (car lst))
  329. (let-values ([(changed-flag result-of-cdr)
  330. (rember-inner (cdr lst))])
  331. (values changed-flag
  332. (cons (car lst)
  333. result-of-cdr)))]
  334. [else
  335. (let-values ([(changed-flag result-of-car)
  336. (rember-inner (car lst))])
  337. (cond
  338. [changed-flag
  339. (values changed-flag
  340. (cons result-of-car (cdr lst)))]
  341. [else
  342. (let-values ([(changed-flag result-of-cdr)
  343. (rember-inner (cdr lst))])
  344. (values changed-flag
  345. (cons (car lst)
  346. result-of-cdr)))]))]))])
  347. (let-values ([(changed-flag result)
  348. (rember-inner lst)])
  349. result))))
  350. </pre>
  351. </div>
  352. <div class="org-src-container">
  353. <pre class="src src-scheme" id="org549a651">
  354. (simple-format
  355. #t "~a\n"
  356. (rember1* '(a (e f g) b (d e f) c d)
  357. (λ (elem) (eq? elem 'e))))
  358. (simple-format
  359. #t "~a\n"
  360. (rember1* '(a (f g) b (d e f) c d)
  361. (λ (elem) (eq? elem 'e))))
  362. (simple-format
  363. #t "~a\n"
  364. (rember1* '(a (f g) b (d f) c d)
  365. (λ (elem) (eq? elem 'e))))
  366. (simple-format
  367. #t "~a\n"
  368. (rember1* '(a (e f g) b (d e f) c d)
  369. (λ (elem) (equal? elem '(e f g)))))
  370. </pre>
  371. </div>
  372. <pre class="example" id="org66b2cb5">
  373. (a (f g) b (d e f) c d)
  374. (a (f g) b (d f) c d)
  375. (a (f g) b (d f) c d)
  376. (a b (d e f) c d)
  377. </pre>
  378. <p>
  379. This works, but the whole <code class="src src-scheme">let-values</code> thing is a bit cumbersome. Furthermore <code class="src src-scheme">let-values</code> has not been introduced in the book at that point. One could of course use a pair or list as a result type as well. Maybe the book has a better solution? Maybe some clever idea with a continuation?
  380. </p>
  381. <p>
  382. The book solves it with an equality function <code class="src src-scheme">eqlist?</code>, which is used to compare the <code class="src src-scheme">car</code> of the list, with the <code class="src src-scheme">car</code> of the list, that potentially has an element removed. Depending on the result of that comparison, it decides to also apply <code class="src src-scheme">rember1*</code> whether to the <code class="src src-scheme">cdr</code> of the list or not. There is an inefficiency in that solution though: We already know, whether we changed something by removing an element of the list in the <code class="src src-scheme">car</code> of the list. If we could return that information, we would not need to do any comparison. This is done in my solution using <code class="src src-scheme">let-values</code>, but could also be done using a pair or list, if one wanted to avoid <code class="src src-scheme">let-values</code>.
  383. </p>
  384. </div>
  385. </div>
  386. <div id="outline-container-chapter-14-avoid-conditionals" class="outline-3">
  387. <h3 id="chapter-14-avoid-conditionals"><span class="section-number-3">2.3.</span> Using continuations to avoid conditionals</h3>
  388. <div class="outline-text-3" id="text-chapter-14-avoid-conditionals">
  389. <p>
  390. The idea is, that often one already knows some fact deeper in recursive calls, but loses that knowledge, when returning values to earlier recursive calls, so one should make use of the knowledge at deeper levels of recursion.
  391. </p>
  392. <p>
  393. Sometimes it takes multiple levels of recursive calls to get to the decisive facts or knowledge. One does not always know ahead of time how to process the return value of recursive calls. It can for example happen, that there is a success case and a failure case. In the success case one might want to put the result values in some kind of data structure (say a list by using cons for example) and in the failure case one might not want to do anything at all with the return values. But one cannot know at this level of recursion whether it will be a success or failure case. Optimistically adding the return values to a data structure might lead to a wrong result. Discarding the return values pessimistically might overlook correct or relevant return values and also lead to a wrong result.
  394. </p>
  395. <p>
  396. There are a few ideas how this can be handled in general:
  397. </p>
  398. <ol class="org-ol">
  399. <li>Run checks on the returned values of recursive calls. Possibly performing redundant checks that already ran as part of deeper levels of recursive calls.</li>
  400. <li>Return all required knowledge in return values up to earlier recursive calls, not merely returning the usual return value, but also knowledge or facts. For example by returning a list or multiple values. The returned knowledge should have a representation, which allows for low-cost checks by the level of the recursion, that needs to run checks on that knowledge. For example the additionally returned facts could be booleans and a check could be, whether some boolean is true or false.</li>
  401. <li>Create a kind of entrypoint to further execution, a continuation, and pass it along with in recursive calls, so that deeper levels of the recursion can decide whether or not to make use of that continuation, depending on their knowledge.</li>
  402. <li>The ugly one: Use an exception, even though no actually exceptional situation is encountered, to jump back to where that exception is handled. This can be seen as a special case of using a continuation though.</li>
  403. <li>Use an other kind of concept that the language used offers. For example GNU Guile offers something called "prompts".</li>
  404. </ol>
  405. <p>
  406. Here we take a look at option 3, using continuations to avoid redundant checks.
  407. </p>
  408. <p>
  409. The following function shows a way to avoid checking the result of a recursive call.
  410. </p>
  411. <div class="org-src-container">
  412. <pre class="src src-scheme" id="orgd04bad3">
  413. (define leftmost
  414. (λ (lst)
  415. (call-with-current-continuation
  416. (λ (return)
  417. (define inner
  418. (λ (lst°)
  419. (cond
  420. [(null? lst°) '()]
  421. [(atom? (car lst°)) (return (car lst°))]
  422. [else
  423. (inner (car lst°))
  424. (inner (cdr lst°))])))
  425. (inner lst)))))
  426. </pre>
  427. </div>
  428. <p>
  429. What happens here?
  430. </p>
  431. <p>
  432. The first call to <code class="src src-scheme">inner</code> inside the <code class="src src-scheme">else</code> branch of the <code class="src src-scheme">cond</code> may or may not find an <code class="src src-scheme">atom?</code> in the <code class="src src-scheme">car</code>. If it finds an <code class="src src-scheme">atom?</code>, it will call the continuation <code class="src src-scheme">return</code> to return it and we forget about running all other memorized calls to <code class="src src-scheme">inner</code>. If it does not find an <code class="src src-scheme">atom?</code>, it will return the empty list <code class="src src-scheme">'()</code>. Nothing is done with that return value and the second call to <code class="src src-scheme">inner</code> with the <code class="src src-scheme">cdr</code> of the list is performed.
  433. </p>
  434. <p>
  435. We could have checked the return value instead, to see whether it is an <code class="src src-scheme">atom?</code> or the empty list and based on that decide to search for a <code class="src src-scheme">leftmost</code> <code class="src src-scheme">atom?</code> in the <code class="src src-scheme">cdr</code>, but that check would have been redundant, since we already know, whether it is an <code class="src src-scheme">atom?</code> in a deeper recursion.
  436. </p>
  437. <div class="org-src-container">
  438. <pre class="src src-scheme" id="org9a53368">
  439. (simple-format
  440. #t "~a\n"
  441. (leftmost '(((a)) b (c))))
  442. (simple-format
  443. #t "~a\n"
  444. (leftmost '((()) b (c))))
  445. (simple-format
  446. #t "~a\n"
  447. (leftmost '(((c a)) b (c))))
  448. (simple-format
  449. #t "~a\n"
  450. (leftmost '(())))
  451. (simple-format
  452. #t "~a\n"
  453. (leftmost '(a b c d)))
  454. </pre>
  455. </div>
  456. <pre class="example" id="orgc5a5ebe">
  457. a
  458. b
  459. c
  460. ()
  461. a
  462. </pre>
  463. </div>
  464. </div>
  465. <div id="outline-container-chapter-14-continuations-needed" class="outline-3">
  466. <h3 id="chapter-14-continuations-needed"><span class="section-number-3">2.4.</span> When are continuations "needed"?</h3>
  467. <div class="outline-text-3" id="text-chapter-14-continuations-needed">
  468. </div>
  469. <div id="outline-container-chapter-14-continuations-needed-success-of-recursive-calls" class="outline-4">
  470. <h4 id="chapter-14-continuations-needed-success-of-recursive-calls"><span class="section-number-4">2.4.1.</span> Unknown success for recursive calls</h4>
  471. <div class="outline-text-4" id="text-chapter-14-continuations-needed-success-of-recursive-calls">
  472. <p>
  473. One scenario in which continuations or another concept that replaces them are needed, when it is not clear at the time of a recursive call, whether the call will achieve the overall goal of the function. For example the book gives code for a function, that removes an element fulfilling a test from an arbitrarily nested list, similar to the following:
  474. </p>
  475. <div class="org-src-container">
  476. <pre class="src src-scheme" id="org46662cb">
  477. (define rm
  478. (λ (elem lst back-out)
  479. (cond
  480. [(null? lst)
  481. ;; If the element cannot be found in the list, call the
  482. ;; continuation back-out, to return to the recursive call and
  483. ;; forget already accumulated conses.
  484. (back-out 'no)]
  485. ;; The next branch checks, whether the car of the list is an atom
  486. ;; and that atom fulfills the predicate we choose. In this case
  487. ;; the predicate is, that it needs to be an atom? and that it
  488. ;; must be eq? to the element we are searching for. But any other
  489. ;; test would be possible as well.
  490. [(atom? (car lst))
  491. (if (eq? (car lst) elem)
  492. ;; If the car is the element we are looking for, simply drop
  493. ;; it.
  494. (cdr lst)
  495. ;; Otherwise keep the car, but look at the cdr of the list.
  496. (cons (car lst)
  497. (rm elem
  498. (cdr lst)
  499. ;; Keep using the same continuation. There is no
  500. ;; need to create a new continuation here. If the
  501. ;; element cannot be found in the cdr of the list
  502. ;; at all, we want to jump back out to the level
  503. ;; above, not back here.
  504. back-out)))]
  505. [else
  506. (let ([new-car
  507. ;; Try to remove the element from the car of the list. It
  508. ;; might or might not exist there. If it exists a
  509. ;; resulting car will be returned, otherwise rm should
  510. ;; call the continuation with an atom as an argument.
  511. ;; Note, that the continuation is created at each point,
  512. ;; where there is a car and a cdr of the list, and that
  513. ;; we only jump back out by 1 level. Depending on the
  514. ;; result of the expression for new-car, we continue from
  515. ;; that level, potentially having to look at the cdr of
  516. ;; the list for removing the searched element. Jumping
  517. ;; back out does not jump all the way up the function
  518. ;; call stack.
  519. (call-with-current-continuation
  520. (λ (back-out)
  521. (rm elem
  522. (car lst)
  523. back-out)))])
  524. ;; Check, whether new-car is an atom?, as in the case, that
  525. ;; the continuation to back out was called.
  526. (if (atom? new-car)
  527. ;; When the element cannot be found in the car of the
  528. ;; list, the continuation back-out is called using an atom
  529. ;; 'no. Otherwise it is not called and the result of the
  530. ;; expression for new-car will be the car of the list with
  531. ;; that one element being removed. If the new-car is an
  532. ;; atom, then the element was not removed from it. That
  533. ;; means the car should stay as is and we need to check
  534. ;; the cdr of the list for the element to remove.
  535. (cons (car lst)
  536. (rm elem
  537. (cdr lst)
  538. back-out))
  539. ;; Otherwise we are done, because the element was already
  540. ;; removed in new-car. We only need to construct the list
  541. ;; as a result.
  542. (cons new-car
  543. (cdr lst))))])))
  544. </pre>
  545. </div>
  546. <p>
  547. This function already expects a continuation as an argument. The idea is, that, if element cannot be found in the whole list, the list stays the same. So instead of backing out and trying to remove it from the cdr of the list, a different logic is required: Keep the whole list.:
  548. </p>
  549. <div class="org-src-container">
  550. <pre class="src src-scheme" id="orgb4bc8b5">
  551. (define rember1*
  552. (λ (elem lst)
  553. (let ([new-list
  554. (call-with-current-continuation
  555. (λ (back-out)
  556. (rm elem lst back-out)))])
  557. ;; Here comes the different logic to handle the result of the
  558. ;; call-with-current-continuation.
  559. (if (atom? new-list)
  560. lst
  561. new-list))))
  562. </pre>
  563. </div>
  564. <p>
  565. We can use it as follows:
  566. </p>
  567. <div class="org-src-container">
  568. <pre class="src src-scheme" id="org6a7b661">
  569. (simple-format
  570. #t "~a\n"
  571. (rember1* 'a '(b c (d (a) e) f g h a)))
  572. </pre>
  573. </div>
  574. <pre class="example" id="org4997e1c">
  575. (b c (d () e) f g h a)
  576. </pre>
  577. <p>
  578. Now contrast this with a function, that is recursive as well, but which does not need continuations. For example the function <code class="src src-scheme">alist-set*</code>, which functionally updates an arbitrarily nested association list:
  579. </p>
  580. <div class="org-src-container">
  581. <pre class="src src-scheme" id="org842a6e5">
  582. (define alist-set*
  583. (lambda* (alst keys val #:key (equal-test equal?))
  584. "Set value VAL inside the alist ALST navigating through its
  585. keys using KEYS to get to the place where VAL shall be the
  586. new value."
  587. (define traverse
  588. (λ (alst keys)
  589. (cond
  590. [(null? keys) val]
  591. [(not (alist?-shallow alst))
  592. (raise-exception
  593. (make-exception (make-non-continuable-error)
  594. (make-exception-with-message "key not found")
  595. (make-exception-with-irritants keys)
  596. (make-exception-with-origin 'alist-set*)))]
  597. [(null? alst) (cons (cons (first keys)
  598. val)
  599. '())]
  600. [else
  601. (let ([current-assoc (first alst)]
  602. [item-key (car (first alst))])
  603. (cond
  604. [(equal-test item-key (first keys))
  605. ;; Change the value and cons the rest of the list.
  606. (cons (cons item-key
  607. (traverse (cdr current-assoc)
  608. (drop keys 1)))
  609. (drop alst 1))]
  610. [else
  611. (cons current-assoc
  612. (traverse (drop alst 1) keys))]))])))
  613. (traverse alst keys)))
  614. </pre>
  615. </div>
  616. <p>
  617. Usage:
  618. </p>
  619. <div class="org-src-container">
  620. <pre class="src src-scheme" id="org0204b2c">
  621. (define myalist '((a . 1)
  622. (b .
  623. ((d . 4)
  624. (e . 5)))
  625. (c . 3)))
  626. (simple-format
  627. #t "~a\n"
  628. (alist-set* myalist '(c) (list (cons 'f 10)) #:equal-test eq?))
  629. </pre>
  630. </div>
  631. <pre class="example" id="org9c80b05">
  632. ((a . 1) (b (d . 4) (e . 5)) (c (f . 10)))
  633. </pre>
  634. <p>
  635. In <code class="src src-scheme">alist-set*</code> we can build up conses correctly without ever building up conses, that we later need to discard, because we get a list of keys, which indicate which association we need to follow, in order to get to the item we are interested in. If such an item does not exist or its keys do not exist, an exception is raised (which could be implemented using continuations, but that would be using continuations for another purpose than <code class="src src-scheme">rm</code> does). If such an item is found, all the conses up to that point are correct and needed. The keys allow us to be sure, that we do not need to back out and look at other associations.
  636. </p>
  637. <p>
  638. We also would not need continuations for <code class="src src-scheme">rm</code>, if it did not only remove one occurrence of the searched element, but all of them. Such a function would not need to forget about conses, but could always check the car and the cdr of a list for occurrences and return for both a potentially updated version. Both branches, the one for the car and the one for the cdr, would always succeed.
  639. </p>
  640. </div>
  641. </div>
  642. </div>
  643. <div id="outline-container-chapter-14-continuations-for-control-flow" class="outline-3">
  644. <h3 id="chapter-14-continuations-for-control-flow"><span class="section-number-3">2.5.</span> Using continuations to build other control flow forms</h3>
  645. <div class="outline-text-3" id="text-chapter-14-continuations-for-control-flow">
  646. <p>
  647. The book shows an intersting control flow form named <code class="src src-scheme">try</code>, which is implemented using continuations. The book uses <code class="src src-scheme">letcc</code>, but here is a slightly different form using <code class="src src-scheme">call-with-current-continuation</code>:
  648. </p>
  649. <div class="org-src-container">
  650. <pre class="src src-scheme" id="org4219f7e">(define try
  651. (λ (proc alternative-proc)
  652. ;; Remember a continuation, which can be used to return a result
  653. ;; for try, if proc succeeds. A success continuation.
  654. (call-with-current-continuation
  655. (λ (success)
  656. ;; Create a continuation, which is used in case of failure of
  657. ;; the given proc.
  658. (call-with-current-continuation
  659. (λ (failure)
  660. ;; The procedure `proc' receives the failure
  661. ;; continuation. If it ever calls the continuation with any
  662. ;; value, there will be a result to the
  663. ;; call-with-current-continuation expression for the failure
  664. ;; case. The failure case continuation is one expression
  665. ;; inside the body of a lambda. This means, that after the
  666. ;; expression is evaluated (has a result), the next
  667. ;; expression will be evaluated, which is the call to
  668. ;; `alternative-proc'.
  669. ;; If instead the call to `proc' returns, without ever
  670. ;; calling `failure', then `success' is instead called,
  671. ;; which jumps out of the lambda and forgets/ignores the
  672. ;; call to `alternative-proc'.
  673. ;; The result of the call to `success' will be the result of
  674. ;; the whole expression `try'.
  675. (success (proc failure))))
  676. (alternative-proc)))))
  677. </pre>
  678. </div>
  679. <p>
  680. Using this <code class="src src-scheme">try</code> definition, we can rewrite <code class="src src-scheme">rember1*</code>:
  681. </p>
  682. <div class="org-src-container">
  683. <pre class="src src-scheme" id="orgcb78f24">
  684. (define rember1*
  685. (λ (elem lst)
  686. (try (λ (failure-cont)
  687. (rm elem lst failure-cont))
  688. (λ () lst))))
  689. (simple-format
  690. #t "success case: removing 'a: ~a\n"
  691. (rember1* 'a
  692. '(b c (d (a) e) f g h a)))
  693. (simple-format
  694. #t "failure case: remaining as is: ~a\n"
  695. (rember1* 'a
  696. '(b c (d (x) e) f g h x)))
  697. </pre>
  698. </div>
  699. <pre class="example" id="org75f3195">
  700. success case: removing 'a: (b c (d () e) f g h a)
  701. failure case: remaining as is: (b c (d (x) e) f g h x)
  702. </pre>
  703. <p>
  704. Of course, defining <code class="src src-scheme">try</code> as a macro could even get rid of the need to write the lambdas in the call of <code class="src src-scheme">try</code>, to make it even more natural.
  705. </p>
  706. <p>
  707. This is also a great example of how continuation passing style (CPS) is very powerful and can make special language constructs unnecessary, even if difficult to read to the untrained eye.
  708. </p>
  709. </div>
  710. </div>
  711. </div>
  712. </div>
  713. <div id="postamble" class="status">
  714. <p class="date">Date: 2023-11-26 Sun 00:00</p>
  715. <p class="author">Author: Zelphir Kaltstahl</p>
  716. <p class="date">Created: 2023-11-26 Sun 11:55</p>
  717. <p class="validation"><a href="https://validator.w3.org/check?uri=referer">Validate</a></p>
  718. </div>
  719. </body>
  720. </html>