I think it should be Tangle.
Program SM-JS (speak, memory).
- Don’t pollute the global namespace.
- Opt out of sloppy mode.
- Program.main.
- Calliope and Mnemosyne.
- Calliope.tellMeWhatToPrint.
- Mnemosyne.tellMeHowToPrint.
- Util.
- Util.transformNumber.
- Util.getArgs.
- javascript (cf. java).
- Invoke Program.main and return.
- Finis.
Introduction
Homer’s Odyssey is the second-oldest extant work of Western literature, the oldest being the Iliad, the prequel to the Odyssey. The Odyssey is about Odysseus returning home to Ithaca after a twenty-year journey during which he “plundered Troy’s sacred heights.” Sheila Murnaghan, in her introduction to Stanley Lombardo’s translation of the Odyssey (Hackett, 2000) says “the Odyssey is, perhaps surprisingly, an epic poem that foregrounds its hero’s experiences in his home with his family, presenting his success in picking up the threads of his previous life as his greatest exploit.” In other words, the Odyssey is a story about returning from a subroutine that produced side-effects to a calling routine, the continued execution of which can be as challenging as any subroutine!
Subroutines are fundamental to computer programming. Knuth, in section 1.4.5 (History and Bibliography) of Volume 1 of The Art of Computer Programming, tells us that “Subroutines were the first labor-saving devices invented for programmers. In the 19th century, Charles Babbage envisioned a library of routines for his Analytic Engine...; and we might say that his dream came true in 1944 when Grace M. Hopper wrote a subroutine for computing sin x on the Harvard Mark I calculator.”
Speak, Memory is the name of the following program. It is how the Lombardo translation of the Odyssey begins. It’s also the title of Vladimir Nabokov’s autobiography, although Nabokov says in the foreword to Speak, Memory, An Autobiography Revisited that he planned to entitle the British edition Speak, Mnemosyne but was told that “little old ladies would not want to ask for a book whose title they could not pronounce.” Speak Memory, the program, is divided into twelve easy-to-follow sections. The comments found in section 3 explain, at a high-level, what this simple little program does. More details are presented in section 6.Calling a subroutine to print the words “hello, world” is at the heart of every implementation of Hello World, the first program to write in any language.1 By now you should have some experience with a few variations of Hello World, and therefore with subroutines. (If not, back up and start at the beginning, for heaven’s sake.) Speak, Memory builds on this experience of yours by demonstrating how subroutines can be used to perform much more complex tasks than simply printing a string of characters. But this is what’s really neat about subroutines: although the goals are usually more complex, a short series of subroutine calls that gets the job done can be just as simple as a Hello, World program! This is because subroutines can hide so many of the nitty-gritty details.
In addition to demonstrating the power of subroutines, Speak, Memory shows how you can create your own subroutines that are no different than subroutines provided by widely-used, standard libraries. If you want, you can mimic the subroutines of other languages. (See section 11, for example.) With practice, discipline, and imagination, you can even use subroutines in one language to create an entirely new programming language of your own design!
Act I.
§1. Don’t pollute the global namespace.
/***************************************************************** ** Program SM-JS (speak, memory). ** Language: JavaScript ** Host: https://errless.blogspot.com ** Path: /p/speak-memory.html#sm-js ** Author: John P. Spurgeon ****************************************************************/ // §1. Obviously, we don’t want to pollute the global namespace. // (Who would want to do that?) So we begin by putting almost all // the source code for our program inside this contraption called // an immediately-invoked function expression or IIFE. (Zero- // emission comments appear before and after the IIFE, and // they’re part of our program’s source code too, but since they // don’t pollute the way some code can, it’s OK that they’re // outside the IIFE.) IIFEs like the one below are often // anonymous. (They don’t have a name.) That’s because we don’t // need to refer to the function by name at some unknown point // in time in the future in order to call it. Instead, we’re // going to execute the function immediately after we define // it, and that will be the one and only time it gets called. // // An IIFE acts sort of like an opaque, sound-proof bubble. If // you’re inside the bubble, you know what people are referring // to when they say the names of things that are also inside the // bubble. But if you’re outside the bubble, you don’t even // know those things exist, because you can’t see them or hear // what people are saying about them. Putting stuff inside an // IIFE is like shutting the door to a classroom so that things // we say inside our room don’t annoy or confuse people in // other rooms who are in ear-shot of ours. If we left the door // open, then someone named Sally in another room might think // that she was being spoken to if she heard us shout out her // name, when in fact we were trying to get the attention of // someone in our room who was also named Sally.(function() {// Outermost IIFE begins here and ends below.
§2. Opt out of sloppy mode.
// §2. We don’t want to be sloppy either, so we evaluate the // string expression "use strict" to opt into strict mode out // of sloppy mode."use strict";
§3. Program.main.
If you don’t know how to pronounce a word, say it loud!” This comical piece of advice struck me as sound at the time, and I still respect it. Why compound ignorance with inaudibility?
Why run and hide?
// §3. OK, now that we’ve taken precautions not to // pollute the environment while we work and have committed // to not being sloppy, we can define, at a high-level, what // it is the program Speak, Memory does when we execute it. /* Our goal is to discover how we can print some specific * string of characters using a mysterious machine called * TOY. For example, maybe we want Speak, Memory to tell us * how to make TOY print the characters “Goodnigt, Moon”, * or we might not be sure what we want to print, and we’d * like the program to suggest something for us to try. */ // Before we look at how Speak, Memory solves this problem, // note that nothing is actually going to happen at this // particular point in the execution of the program. (A // JavaScript interpreter will execute the instructions // one-by-one in the same order that they are presented here, // assuming the sections of code don't get shuffled around.) // Not only have we just begun to define the IIFE prior to // executing it, but even if we weren’t using an IIFE, this // is only where we declare and initialize an object called // Program that has a subroutine or method called main that // is capable of doing something. // // We don’t get around to calling the main subroutine // until just before we reach the very end of the outermost // IIFE. (See §11.) We can’t expect the main program to // function properly until all of the lower-level methods // that main depends on are defined. Defining those nitty- // gritty details is what we do in sections §4 – §10. // Let’s look at some more code now. To being with, we // declare and initialize a constant variable named Program. // We don’t actually have to do this; in JavaScript, we // could just define the function main (we don’t even have // to call it “main”), but we don’t want to be sloppy, and // one way to keep things nice and neat is to put related // things in packages we call objects. Granted, we’re // only putting one thing (i.e. main) in the Program object, // so you might think it’s not worth the bother, and it’s hard // to refute that argument. But the name “Program” adds some // nice context, I think. It’s sort of like an adjective in // English. (Although it’s a noun, of course.) Furthermore, // Speak, Memory is full of allusions, mimicry, and even // a little mockery here and there. This is one place where // we are mimicking, if not mocking, the Java programming // language. (Not that there’s anything wrong with Java, // of course.)const Program = {// We declare main to be a function that resides inside the // object now known as Program, and we define the function.main: function(args) {// First, we ask our muse Calliope to tell us what text // she thinks we should print. If we have something in // mind then that possibility (or those possibilities) will // be stored in some location we refer to via the parameter // variable named args, which we pass to Calliope when we // call tellMeWhatToPrint. Calliope examines the value of // the thing or things args refers to and returns her // advice. See §5 if you want to know exactly how Calliope // makes up her mind about what we should do. See §9 and // §11 for the nitty-gritty details of how any ideas we // have get passed into the program and wind up in the // location referred to by args in the first place.const text = Calliope.tellMeWhatToPrint(args);// Now that we have our inspired text in hand, we ask // Mnemosyne to tell us how to print it using that machine // we’re calling TOY. (We’ll learn more about TOY in §6.) // To get the instructions from “Mnemosyne” (the highbrow // variable name we’re using to refer to a simple JavaScript // object) we pass the value of the constant variable named // text to Mneumosyne’s tellMeHowToPrint method and store // the value Mneumosyne returns in the constant variable // named how.const how = Mnemosyne.tellMeHowToPrint(text);// Next, we use the Java-like object System.out (see §10) // to open a web page, and we write the instructions that // Mnemosyne returned to us on it.System.out.open("about:blank"); System.out.writeLine(how);// If everything went as planned and the page is ready, // then we print it. We encourage the user to close // the page afterwards, since too many open pages clutter // up the screen. However, the user might want to leave // the page open if, for example, the print job was // canceled due to the lack of a actual printer and the // user still wants to read the instructions. So the user // gets to decide when to close the page.if (System.out.ready()) { System.out.print(); if (confirm("Press OK to close page.")) { System.out.close(); } }// Finally, we check to see whether the page // was closed and return a message accordingly.return System.out.ready() ? "Remember to close the page." : "Good!" } };
Intermission.
Act II
of how low-level details make it possible to achieve high-level goals.
§4. Calliope and Mnemosyne.
// §4. Here is where we introduce Calliope and Mnemosyne // and declare their names to be constant variables. // We’ve encountered this phrase “constant // variable” before, and we really need to know what it // means. Now’s as good a time as any to briefly digress // and talk about it. // // The phrase constant variable might seem // oxymoronic, but it makes sense if you look at the right // way. You see, Calliope, for example, could be the name of // a variety of things: the number 2, the string "hello", the // object {}, the array [1, "two", 3], etc. In that regard, // Calliope is variable. But since Calliope is a constant // variable, once we have decided what thing she should refer // to initially, we can’t suddenly change our mind and let // her name refer to something else. (If we wanted that sort // of freedom, we could introduce her name using the phase // “let Calliope” or “var Calliope” instead.) Now, the thing // Calliope refers to might somehow change, but the name // Calliope (this particular instance of the name, that is) // can’t suddenly refer to something else altogether, if // that make any sense. So the phrase “const Calliope” // not only introduces the variable name Calliope, it // introduces a constant variable name. But there’s more to // the story than that! Because Calliope and Mnemosyne // are constant variable names, we must we must decide what // they are going to refer to here and now. We can’t announce // that that they are constant variables here and give them // initial/permanent values later. Those are the rules.const Calliope = {};// Homer’s muse.const Mnemosyne = {};// Goddess of memory.// Addendum: See JavaScript object basics.
§5. Calliope.tellMeWhatToPrint.
// §5. Calliope is the muse who presides over eloquence and // epic poetry. If you haven’t heard someone say her name yet, // then you might be wondering how to pronounce it. Calliope // rhymes with “don’t lie to me” (I made that up myself), // and if you tried to write it like it sounds, you might // come up with something like kuh-LI-uh-pee, where dashes // separate the syllables and the stressed syllable is written // in uppercase. // // Calliope examines the input we give her and responds with // some text that we should print. Assuming we have interesting // ideas of our own, she always tells us to print the first // thing on the list we pass her. But if we have writer’s block // and don't give her any good choices to choose from, then // she'll help us think of something. Granted, her plan B is // always the same.Calliope.tellMeWhatToPrint = function(options) { function firstOptionIsOk(array) { return typeof array === "object" && array.hasOwnProperty("length") && array.length > 0 && typeof array[0] === "string" && array[0].length > 0; } const planB = "少出错"; return firstOptionIsOk(options) ? options[0] : planB; };// Addendum: // http://hanzidb.org/character/少 shao3 // http://hanzidb.org/character/出 chu1 // http://hanzidb.org/character/错 cuo4
§6. Mnemosyne.tellMeHowToPrint.
// §6. Mnemosyne, nuh-MA-sin-ee (like "no moss on me"), is the // goddess of memory and the mother of the arts and sciences. // We pass her something we want to print (it could be what // Calliope told us to print or something else entirely) and // Mnemosyne tells us how to print it using TOY — that little // machine we’ve been talking about.Mnemosyne.tellMeHowToPrint = function(string) {// Constant local variables.const Base = 16, MinAddrDigits = 2, MinDataDigits = 4, BR = System.getLineBreak();// A title should describe the procedure.let proc = "How to print \"" + string + "\" using TOY." + BR;// We need to load codes denoting characters into the very // last address of some TOY machine. Presumably the maker // of the machine is in cahoots with whoever devised this // scheme and has wired things up so that the characters // corresponding to whatever codes we load will be displayed // on some sort of output device. This boils down to // setting the ADDR field of the machine to the hexadecimal // number 0xff, assuming the machine is like the one // Bob Sedgewick and Kevin Wayne describe in chapter 6 of // Computer Science, An Interdisciplinary Approach, // a legendary textbook published by Addison Wesley in 2017.const LastAddr = Util.transformNumber({ decimalNum: 0xff, radix: Base, minDigits: MinAddrDigits }); let step = "Set the ADDR switches to " + LastAddr + "."; proc += BR + "Step 1. " + step;// The remaining steps are all very similar. The only thing // that varies, besides the step number, is the value of // the character code to be loaded into the last memory // location of the TOY computer.const n = string.length; for (let i = 0; i < n; i++) { const code = string.charCodeAt(i); const data = Util.transformNumber({ decimalNum: code, radix: Base, minDigits: MinDataDigits }); step = "Set the DATA switches to " + data; step += ", then press LOAD."; proc += BR + "Step " + (i + 2) + ". " + step; }// Speak, Mnemosyne (i.e. return the procedure).return proc; };
Act III.
Joyce’s final novel, Finnegans Wake, was 17 years in the making and is an entirely unprecedented (an to many, unintelligible) journey into the psyche of nocturnal Dublin. In an attempt to capture the vocabulary of sleep and dreams, Joyce discarded not only traditional narrative, but also the English language itself.
§7. Util.
// §7. Lets bundle the following subroutines together // in an object called Daedalus is pronounced DAY-da-lus or // or DEE-da-lus or DEAD-a-lus but I bet someone will chafe // at the allusion Joyce is a language too maybe Util is better // and cat is a tool I wonder do they see anything that we cant // staring like that when she sits at the top of the stairs so // long and listening as I wait always what a robber too that // lovely fresh place I bought I think Ill get a bit of fish // tomorrow or today is it Friday yes I will with some // blancmange with black currant jam like long ago not those // 2 lb pots of mixed plum and apple from the London and // Newcastleconst Util = {};// Assorted subroutines.
§8. Util.transformNumber.
// §8. Util.transformNumber.Util.transformNumber = function(args) { console.assert(args.hasOwnProperty("decimalNum")); console.assert(args.hasOwnProperty("radix")); console.assert(args.hasOwnProperty("minDigits")); function getNumberPrefix(radix) { return (radix === 16) ? "#" : ""; } function padWithLeadingZeros(string, minLength) { const n = string.length; let zeros = ""; for (let count = n; count < minLength; count++) zeros += "0"; return zeros + string; } const numStr = args.decimalNum.toString(args.radix); const prefix = getNumberPrefix(args.radix); return prefix + padWithLeadingZeros(numStr, args.minDigits); };
§9. Util.getArgs.
// §9. Util.getArgs.Util.getArgs = function() { function splitInputIntoPieces(string) { return (string === null || string.length === 0) ? [] : string.split(","); } const source = javascript.lang.System.in; const string = source.ready() ? source.read() : null; return splitInputIntoPieces(string); };
Act IV.
§10. javascript (cf. java)
// §10. javascript (cf. java)const javascript = { io: {}, lang: {} }; javascript.io.InputElement = function(inputElementId) { const inputElement = document.getElementById(inputElementId); this.ready = function() { return inputElement !== null; }; this.read = function() { return inputElement.value; }; }; javascript.io.WebPage = function() { const that = this; const bufferLimit = 100; let qtyFlushed = 0; let buffer = ""; let win = null; let doc = null; this.ready = function() { return doc !== null; }; this.print = function() { if (that.ready()) win.print(); }; this.write = function(x) { if (x !== undefined && x !== null) buffer += x.toString(); if (buffer.length - qtyFlushed > bufferLimit) that.flush(); }; this.writeLine = function(x) { that.write(x.toString() + System.getLineBreak()); that.flush(); }; this.flush = function() { if (that.ready() && buffer.length > qtyFlushed) { doc.write(buffer); qtyFlushed = buffer.length; } }; this.open = function(url) { win = window.open(url); if (win === null) return; doc = win.document; that.flush(); }; this.close = function() { if (win !== null) win.close(); win = doc = null; }; }; javascript.lang.System = { in: new javascript.io.InputElement("input"), out: new javascript.io.WebPage("about:blank"), getLineBreak: function() { return "<" + "br>"; } }; const System = javascript.lang.System;
§11. Invoke Program.main and return.
// §11. Now that everything is defined, we can call the method // Program.main. Before we do that, however, we invoke // Util.getArgs to get a value which will be the argument that // we pass to the main method. When Program.main completes, it // will return a value (which might be undefined) and we'll // in turn return that value to terminate the immediately- // invoked function expression (IIFE). See §1 and §12.return Program.main(Util.getArgs());
§12. Finis.
// §12. The End.})();// Outermost IIFE ends on this line. /***************************************************************** Speak, Memory — Of the cunning hero, The wanderer, blown off course time and again After he plundered Troy’s sacred heights. — HOMER, Odyssey Among the anomalies of a memory, whose possessor and victim should never have tried to become an autobiographer, the worst is the inclination to equate in retrospect my age with that of the century. This has led to a series of remarkably consistent chronological blunders in the first version of this book. I was born in April 1899, and naturally, during the first third of, say, 1903, was roughly three years old; but in the August of that year, the sharp “3” revealed to me (as described in “Perfect Past”) should refer to the century’s age, not mine, which was “4” and as square and resilient as a rubber pillow. — VLADIMIR NABOKIV, Speak Memory, An Autobiography Revisited (1966) *****************************************************************/ // Copyright © 2018 John P. Spurgeon
Subroutines are used to save space in a program. The do not save any time, other than the time implicitly save by having less space - for example, less time to load the program, and better use of high-speed memory on machines with several grades of memory. The extra time taken to enter and leave a subroutine is usually negligible, except in critical innermost loops. ...
Subroutines have several other advantages. They make it easier to visualize the structure of a large and complex program; they form a logical segmentation of the entire problem, and this usually makes debugging of the program easier. Many subroutines have additional value because they can be used by people other than the programmer of the subroutine.Most computer installations have built up a large library of subroutines, and such a library greatly facilitates the programming of standard computer applications that arise. A programmer should not think of this as the only purpose of subroutines, however; subroutines should not always be regarded as general-purpose programs to be used by the community. Special-purpose subroutines are just as important, even when they are intended to appear in only one program.