on master help sign in
Update hoon-4-lispers.md
commit5bc898bc0b9eb41468de4833abefb580fd6199c0 authorSigilante <57601680+sigilante@users.noreply.github.com> dateThu 15 Jun 2023, 10:50 (3 years ago) parent91c25f0
1 file changed+95−52
content/blog/hoon-4-lispers.md+95−52
content/blog/hoon-4-lispers.md+95−52
@@ -1,6 +1,6 @@
11+++
22title = "Hoon for Lispers"
3−date = "2023-06-13"
3+date = "2023-06-15"
44description = "Lisp is an éminence grise of programming. How does Hoon compare?"
55
66[extra]
@@ -13,40 +13,36 @@ image = "https://engineering.stanford.edu/sites/default/files/styles/card_1900x9
1313
1414> In the beginning, von Neumann created the machine. And the machine was with rigorous form and code, and no compiler yet moved upon the face of the tubes. And the evening and the morning were the first day.
1515>
16−> And John Backus said, Let there be FORTRAN, and there was FORTRAN. And FORTRAN ruled over the assembly.
16+> And John Backus said, Let there be FORTRAN, and there was Fortran. And Fortran ruled over the assembly.
1717>
1818> And John McCarthy saw the lambda calculus, that it was very good. And McCarthy made the LISP and divided the programmers who were for the array from the programmers who were for the list.
1919>
20−> And the FORTRAN and the LISP were the second day. And God set them in the firmament to give light upon the earth.
20+> And the Fortran and the Lisp were the second day. And God set them in the firmament to give light upon the earth.
2121
2222Two great temperaments of programming language design span these poles: Fortran as the engineer of assembler-first hard-nosed array coding and Lisp as the math professor running down to the machine room waving papers. While they have ceded some to the practicalities of the other over time, each is a trope of a particular computing paradigm. In this article, we will examine the Lisp pole in light of Urbit's development language, Hoon.
2323
2424Hoon is a statically typed functional programming language that is designed to be safe, efficient, and expressive. Hoon has a unique syntax relying heavily on symbolic expressions (using “runes”) rather than traditional keywords and operators. Hoon's underlying execution language, Nock, has been described as a “pico-Lisp“, making reference to its nature as a cell-based combinator calculus. Both languages (Nock and Hoon) follow very much in the philosophical steps of Lisp but seek to improve the genre.
2525
26−Lisp is known for its powerful macro system, which allows developers to write code that generates more code at compile time, and for its powerful `eval` statement; while Hoon provides a flexible metaprogramming system that allows developers to manipulate code at compile time and hot-swap code at runtime.
26+Lisp is known for its powerful macro system, which allows developers to write code that generates more code at compile time, and for its powerful `eval` function; while Hoon provides a flexible metaprogramming system that allows developers to manipulate code at compile time and hot-swap code at runtime.
2727
28−This article will contrast classical Lisp syntax and assumptions with Hoon's design. Three overarching design principles have yielded the necessary components of Hoon's characteristic structure:
28+This article will contrast classical Lisp syntax and assumptions with Hoon's design. As Lisp is a family of languages rather than a single implementation, I will strive to make generally applicable statements or qualify the discussion—I welcome nuance in your responses about the different major Lisp dialects.
29+
30+Hoon's characteristic structure has arisen from these overarching design principles:
2931
30321. Hoon must compile to Nock, and benefits from reflecting Nock's calculational worldview.
31332. Hoon must be capable of live upgrades; that is, conscious brain surgery on itself.
32−3. Hoon should grow organically based on actual developer usage patterns (and it did).
33−
34−(There has, of course, also been organic evolution as core developers discovered particular design patterns and designed appropriately concise syntax.)
34+3. Hoon should grow organically based on actual developer usage patterns.
3535
36−Our investigation of Lisp and Hoon will cover:
37−
38−1. Syntax
39−2. Metaprogramming
40−3. Philosophy
36+Our investigation of Lisp and Hoon will compare their syntax, their metaprogramming affordances, and their underlying philosophies.
4137
4238
4339## Syntax
4440
45−Hoon has many commonalities with Lisp and its most common calling convention is sugared to appear like Lisp. The syntax of Nock differs—e.g. using `[]` brackets instead of `()` parentheses—and Nock does not have non-numeric tokens or names. Hoon serves as a more human-friendly syntax which mediates common expressions and structures much as C overlays assembly language. For practical purposes, we never need to write Nock code by hand, and so while Nock informs Hoon's design choices, we don't need to understand any Nock to talk about Hoon.
41+Hoon has many commonalities with Lisp and its most common calling convention is sugared to appear like Lisp. The conventions of Nock differ—e.g. using `[]` brackets instead of `()` parentheses—and Nock does not have non-numeric tokens or names. Hoon serves as a more human-friendly syntax which mediates common expressions and structures much as C overlays assembly language. For practical purposes, we never need to write Nock code by hand, and so while Nock informs Hoon's design choices, we don't need to understand any Nock to talk about Hoon.
4642
4743Both Lisp and Hoon are homoiconic, meaning that code and data are directly represented the same way: Lisp code is represented as Lisp data structures, and Hoon code is represented as Hoon data structures. Homoiconicity means that code can be manipulated and transformed as data at runtime. While the most compelling investigation in this article focuses on metaprogramming, we need to start with a comparative syntax and grammar so we understand how code and data are represented.
4844
49−Before all of that, let us compare a simple program implemented in both Lisp and Hoon. Since both programming languages are functional languages that result in values and prefer to avoid side effects, we will not use a trivial “Hello World” example. Instead we will calculate the arithmetic mean of a set of numbers of known size.
45+Before all of that, let us compare a simple program implemented in both Lisp and Hoon. Both programming languages are species of functional languages for which expressions result in values, but they handle side effects differently: in Hoon side effects are strictly impossible (although a runtime workaround permits I/O and necessary effects), while in Lisp side effects are permitted (although opinions on their use vary). We will therefore not use a trivial “Hello World” example. Instead we will calculate the arithmetic mean of a set of numbers of known size.
5046
5147```scheme
5248(define (mean a)
@@ -73,9 +69,9 @@ Before all of that, let us compare a simple program implemented in both Lisp and
7369
7470The Scheme code has the advantage that it reads almost English-like as one works through the logic, but implicitly relies on familiarity with the `if`/`then`/`else` structure and function application using `()` (on which more soon).
7571
76−The Hoon code uses the `%` function application runes (differentiated by number of arguments) to apply the function calls. With syntactical sugar, this looks similar to the Lisp call, with `++roll` instead of `apply` and `++lent` instead of `length`.
72+The Hoon code uses the `%` function application runes (differentiated by number of arguments) to apply the function calls. With syntactic sugar, this looks similar to the Lisp call, with `++roll` instead of `apply` and `++lent` instead of `length`.
7773
78−Throughout I will use code examples for Lisp written in the Scheme dialect taken from [Rosetta Code](https://rosettacode.org/wiki/Category:Scheme). I will select or compose Hoon examples to be structurally similar to the Lisp code in order to facilitate comparison. I will also avoid sugar syntax that would obscure the structure of the Hoon code; in some cases this will make it slightly less readable than its equivalent in practice.
74+Throughout I will use code examples for Lisp taken from [Rosetta Code](https://rosettacode.org/wiki/Category:Scheme). I will select or compose Hoon examples to be structurally similar to the Lisp code in order to facilitate comparison. I will also avoid sugar syntax that would obscure the structure of the Hoon code; in some cases this will make it slightly less readable than its equivalent in practice.
7975
8076### Syntax in Lisp
8177
@@ -100,7 +96,7 @@ Lisp code, being dynamically typed, is inclined to try a value and see if it wor
10096
10197Lisp types are to some extent (justly) influenced by the underlying platform architecture: Lisp is generally compiled directly to machine code (like a C program), with the notable exception of [Clojure](https://clojure.org/reference/lisps) which runs on the Java Virtual Machine.
10298
103−#### Operators, Functions, and Macros
99+#### Operators, Functions, Macros, and Thunks
104100
105101Lisp syntax is characterized by its use of nested lists, called S-expressions (symbolic expressions), which consist of parentheses enclosing atoms or other S-expressions. The basic structure of an S-expression is an operator (or function) followed by its arguments, all enclosed in parentheses. For example, the following S-expression performs a simple arithmetic operation:
106102
@@ -108,11 +104,11 @@ Lisp syntax is characterized by its use of nested lists, called S-expressions (s
108104(+ 1 2 3)
109105```
110106
111−Lisp uses prefix notation, where the operator comes before the operands, and parentheses are used to group expressions. The S-expression is evaluated from left to right, with the operator being applied to its arguments.
107+Lisp uses prefix notation, where the operator comes before the operands, and parentheses are used to group expressions. The S-expression is evaluated from left to right (in most Lisps save Scheme), with the operator being applied to its arguments.
112108
113109Operators in Lisp operate on values of different basic types. Lisp dialects vary in their particular base types, but typically include numbers, strings, booleans, and so forth. The core data type is the list, of course (LISP is for LISt Processing). Since Lisp biases towards list processing, many operators are comfortable receiving an arbitrary number of values as inputs, as in the code sample above.
114110
115−In Lisp, [`cons`](https://en.wikipedia.org/wiki/Cons) describes the procedure to construct a pair of pointers to objects. This seemingly modest capability is fundamental to how Lisp builds lists—and since everything is a list, `cons` has consequences. One fundamental convention is the `cons` cell, which consists of pointers to two other Lisp objects and is how lists are actually constructed.
111+In Lisp, [`cons`](https://en.wikipedia.org/wiki/Cons) describes the procedure to construct a pair of objects. This seemingly modest capability is fundamental to how Lisp builds lists—and since everything is a list, `cons` has consequences. One fundamental convention is the `cons` cell, which consists of two other Lisp objects and is how lists are actually constructed.
116112
117113![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/Cons-cells.svg/450px-Cons-cells.svg.png)
118114
@@ -132,7 +128,7 @@ SQUARE
132128
133129Lisp functions are first-class objects and can be manipulated and passed like values of basic types as well.
134130
135−Before we can look at macros, we need to consider Lisp's notion of evaluation and in particular deferred evaluation. For Lisp, an expression can be marked as a literal value rather than evaluated to produce a result. The quote `'` symbol is used to mark expressions for such deferred evaluation:
131+Before we can look at macros, we need to consider Lisp's notion of evaluation and in particular deferred evaluation. For Lisp, an expression can be marked as a literal value rather than evaluated to produce a result. The quote `'` symbol is used to mark expressions for prevented evaluation:
136132
137133```lisp
138134'(1 2 3) ; evaluates to the list (1 2 3)
@@ -149,7 +145,7 @@ Backtic or backquote `` ` `` allows you to switch an expression in and out of ev
149145`(1 ,(+ 2 3)) ; evaluates to the list (1 5)
150146```
151147
152−A Lisp macro differs slightly from a function in that it uses deferred evaluation to produce an example later.
148+A Lisp macro is essentially a compile-time function.
153149
154150```lisp
155151> (defmacro square (x)
@@ -162,9 +158,25 @@ A Lisp macro differs slightly from a function in that it uses deferred evaluatio
162158
163159(The `` ` `` notation constructs the expression with values spliced in by `,`.)
164160
165−In Lisp, the `eval` operator is used to evaluate a Lisp expression that is represented as a data structure. It takes a single argument, which is a Lisp expression, and returns the value of that expression.
161+A deferred evaluation, called a thunk, is a closure that inherits its lexical environment but is deferred for later computation. Thunks enable lazy code evaluation and separate the computation’s definition from its execution.
162+
163+```lisp
164+(defun create-thunk (function &rest arguments)
165+ (lambda () (apply function arguments)))
166+
167+(defun invoke-thunk (thunk)
168+ (funcall thunk))
166169
167−The `eval` operator is a powerful tool in Lisp, because it allows Lisp programs to manipulate and evaluate Lisp code dynamically at runtime. This means that Lisp programs can generate new code and evaluate it on the fly, allowing for a high degree of flexibility and adaptability.
170+;; Creating a thunk that calculates the factorial of a number
171+(defvar factorial-thunk (create-thunk #'(lambda () (factorial 5))))
172+
173+;; Invoking the thunk to get the result
174+(print (invoke-thunk factorial-thunk)) ; Output: 120
175+```
176+
177+In this code example, `create-thunk` accepts a function and returns a thunk created using a lambda function to encapsulate the computation. `invoke-thunk` is used to invoke the thunk to get the actual result. The actual application creates a deferred factorial implementation and then finally invokes it. Without the last line, the actual calculation would never be executed.
178+
179+As Paul Graham wrote, “The unusual thing about Lisp-- in fact, the defining quality of Lisp-- is that it can be written in itself.” A Lisp program is an S-expression, and in principle we can run the equation the other way: certain S-expressions are valid Lisp programs. Although uncommon in practice due to code safety issues, the `eval` function is illustrative of Lisps’ ability to evaluate a Lisp expression that is represented as a data structure. It takes a single argument, which is a Lisp expression, and returns the value of that expression. Lisp programs can in principle generate new code—or modify existing code—and evaluate it on the fly, since code is data.
168180
169181```lisp
170182(defvar x 10)
@@ -174,8 +186,6 @@ The `eval` operator is a powerful tool in Lisp, because it allows Lisp programs
174186(eval z)
175187```
176188
177−`eval` lets us resolve the deferred expression when we are ready to use it. Code introspection in Lisp is straightforward because of deferred evaluation: one can look inside of a function to see how it works.
178−
179189Besides explicitly named functions and macros, Lisp frequently employs lambda expressions to produce functions on demand at the point of use.
180190
181191```lisp
@@ -246,7 +256,7 @@ A cell is a pair of two nouns, and of course many compound types exist, includin
246256
247257Hoon expressions are ultimately binary trees of cells and atoms—Hoon is homoiconic and so code is directly represented as a data structure which can be interpreted as a value as well. This facilitates Hoon's ability to upgrade itself in place, as we will see.
248258
249−Hoon implements types as _molds_, or functions which coerce to type or crash. A mold is a way of asserting known type information over a value, typically at compile time, in a way that allows for data transformation and data validation. This leads to some interesting cases such as the difference between a null-terminated tuple and a true list, which some functions require.
259+Hoon commonly implements types structurally via _molds_, or functions which coerce to type or crash. A mold is a way of asserting known type information over a value, typically at compile time, in a way that allows for data transformation and data validation. This leads to some interesting cases such as the difference between a null-terminated tuple and a true list, which some functions require.
250260
251261```hoon
252262> ~[1 2 3]
@@ -303,16 +313,16 @@ A `vase` can be used at runtime to resolve a value from a dynamic context into a
303313
304314#### Expressions
305315
306−Nock explicitly consists of binary trees, since any Nock structure or program consists entirely of atoms (bare values) and cells (pairs of nouns). Although Hoon ultimately compiles to Nock, it is more natural in some ways to approach the syntax of a program as an array of $n$-ary trees, where each “slot” in an expression can have zero, one, or many children. (Zero children refers to a tree address containing a terminal value like a symbol or an integer.)
316+Nock explicitly consists of binary trees, since any Nock structure or program consists entirely of atoms (bare values) and cells (pairs of nouns).
307317
308−image here TODO
318+![](https://storage.googleapis.com/media.urbit.org/docs/userspace/hoon-school/binary-tree.png)
309319
310320Expressions are oriented around runes, which act as operators to join or manipulate expressions. To construct a cell of two values like `1` and `2`, one uses the `:-` cencol rune. (Hoon cells implement what we call an “implicit `cons`”, meaning that two nouns composed together are simply unified in a shared binary tree.)
311321
312322```
313323 :-
314324 / \
315−1 2
325+1 2
316326```
317327
318328To invoke a function named `add`, one can provide a `%-` cenhep rune with the function name and the arguments.
@@ -321,8 +331,8 @@ To invoke a function named `add`, one can provide a `%-` cenhep rune with the fu
321331 %-
322332 / \
323333add :-
324− / \
325− 1 2
334+ / \
335+ 1 2
326336```
327337
328338We write this Hoon expression one of two ways, either separated by whitespace or using parentheses:
@@ -344,6 +354,8 @@ Hoon employs “sugar syntax” for many common code patterns to make them easie
344354
345355which results in basically the same expression once the parser is done.
346356
357+(Although Hoon ultimately compiles to Nock, it is more natural in some ways to approach the syntax of a program as an array of $n$-ary trees, where each “slot” in an expression can have zero, one, or many children. Zero children refers to a tree address containing a terminal value like a symbol or an integer.)
358+
347359Rune syntax is Hoon's answer to the Lisp proliferation of parentheses—by restricting expressions to a definite number of children, Hoon avoids needing to explicitly terminate most expressions. In some ways, runes are an ASCII-based equivalent of APL's symbolic character operators.
348360
349361```apl
@@ -380,18 +392,18 @@ The next examples explore an interesting difference between Lisp `cond` and Hoon
380392 %typical-midwest
381393++ symbol-to-message
382394 |= msg=term
383− ?+ msg 'Typical Midwest'
384− %too-hot
385− 'Too hot outside'
386− %nice
387− 'Nice outside'
388− %too-cold
389− 'Too cold here'
395+ ?+ msg 'Typical Midwest'
396+ %too-hot
397+ 'Too hot outside'
398+ %nice
399+ 'Nice outside'
400+ %too-cold
401+ 'Too cold here'
390402 ==
391403--
392404```
393405
394−Lisp expects a program to be a running series of expressions, naturally composed together as a list. Hoon, in contrast, requires everything to be a binary tree: thus, series of expressions must be composed together, e.g. using `=>` tisgar to concatenate two expressions.
406+Lisp expects a program to be a running series of expressions, naturally composed together as a list. Hoon, in contrast, expects everything to be an evaluable expression (no implicit `progn`, for instance): thus, series of expressions must be composed together, e.g. using `=>` tisgar to concatenate two expressions.
395407
396408This code example defines an expression and immediately evaluates another expression against it:
397409
@@ -426,6 +438,8 @@ Hoon has much more syntactic sugar than Lisp. Not only is the Lisp-like `()` ex
426438
427439This gives a Hoon developer an extreme amount of flexibility in constructing and laying out code expressions. In fact, many Hoon programs read as a hybrid of imperative code and functional code, since the ability to lay out intent line-by-line feels rather like C.
428440
441+Hoon conventions and sugar syntax have evolved organically as core developers discovered or invented useful design patterns and appropriately concise syntax.
442+
429443#### Functions (Gates) and Cores
430444
431445The most important structural concept in Hoon is the core, which organizes code into a binary tree of `[code data]`, or as we call it in Hoon, `[battery payload]`. Since cores have a standard structure, this means that many kinds of direct manipulations (metaprogramming) are possible, such as altering the input arguments to a function or manipulating the code variance model. Cores play a role in Hoon similar to that of objects in many other languages.
@@ -514,7 +528,7 @@ The nature of cores derives from Nock and is key to understanding how Hoon works
514528--
515529```
516530
517−Although Lisp's `'` quote deferred evaluation operator has no direct equivalent in Hoon, there are a couple of structures that can provide a similar effect. The most important of these is the `|.` trap, which defines an expression to be evaluated at a later time. For instance, traps are used when testing code that _should_ fail, as the expression can be defined and deferred until the test framework is ready to process it.
531+Although Lisp's `'` quoting has no direct equivalent in Hoon, there are a couple of structures that can provide a similar effect. The most important of these is the `|.` trap, which defines an expression to be evaluated at a later time—Hoon’s equivalent of Lisp’s thunk. For instance, traps are used when testing code that _should_ fail, as the expression can be defined and deferred until the test framework is ready to process it.
518532
519533```hoon
520534> =foo |.((add 1 41))
@@ -541,11 +555,44 @@ To use `++turn`, we need a list and a transformation function. The type of the
541555
542556Wet gates are therefore used when incoming type information is not well known and needs to be preserved. This includes parsing, building, and structuring arbitrary nouns. (Beyond Lisp analogues, you can think of C++'s templates and operator overloading, and Haskell's typeclasses.)
543557
558+This example compares the Lisp deferred factorial thunk with an equivalent Hoon trap. (Hoon includes `++factorial` since it is not part of the standard library.)
559+
560+```scheme
561+(defun create-thunk (function &rest arguments)
562+ (lambda () (apply function arguments)))
563+
564+(defun invoke-thunk (thunk)
565+ (funcall thunk))
566+
567+;; Creating a thunk that calculates the factorial of a number
568+(defvar factorial-thunk (create-thunk #'(lambda () (factorial 5))))
569+
570+;; Invoking the thunk to get the result
571+(print (invoke-thunk factorial-thunk)) ; Output: 120
572+```
573+
574+```hoon
575+=>
576+|%
577+++ factorial
578+ |= n=@ud
579+ |-
580+ ?: =(n 1) 1
581+ %+ mul n
582+ %= $
583+ n (dec n)
584+ ==
585+++ factorial-5
586+ |. (factorial 5)
587+--
588+(factorial-5)
589+```
590+
544591### Subject-Oriented Programming
545592
546593Urbit programming employs a paradigm deriving from the nature of Nock (_a fortiori_ Hoon), subject-oriented programming. Every expression of Hoon is evaluated relative to its subject, a piece of data that represents the environment, or the context, of an expression.
547594
548−The subject refers to the parent binary tree of an expression, more or less, and serves as state, lexical scope, environment, and function argument. (We can be precise about the definition in all cases—e.g. the subject of a gate in a core is the core itself—but don't need to for this essay.) The compile-time environment in ([some dialects of](https://www.gnu.org/software/emacs/manual/html_node/elisp/Variable-Scoping.html)) Lisp has dynamic extent, such that any part of the program can access a particular binding. Hoon's subject-oriented programming model takes this even further: since code and data share the same representation, and code is a binary tree, any part of the subject is available in principle.
595+The subject refers to the parent binary tree of an expression, more or less, and serves as state, lexical scope, environment, and function argument. (We can be precise about the definition in all cases—e.g. the subject of a gate in a core is the core itself—but don't need to for this essay.) Lisp supports variable scope and global variables, such that any part of the program can access a particular binding. Hoon's subject-oriented programming model naturally provides its equivalent of scope: all code is evaluated against a subject and name bindings proceed by depth-first match (with permitted skips to prevent unwanted masking).
549596
550597> Subject orientation in Nock and Hoon stems partly from minimalism (there's just one subject, which serves as state, lexical scope, environment, and function argument), partly from a desire to simplify compilation (the type of the subject is a full specification of the compile-time environment for a source file), and partly in order to give the language a more imperative feel.
551598>
@@ -575,7 +622,7 @@ because the `++add` gate is not defined in the subject against which the express
575622
576623```scheme
577624(define index-of
578− (lambda (needle hackstack)
625+ (lambda (needle haystack)
579626 (let ((tail (member needle haystack)))
580627 (if tail
581628 (- (length haystack) (length tail))
@@ -635,21 +682,17 @@ A Lisp program is really a list, or a list of lists (nested as much as necessary
635682
636683### Metaprogramming in Lisp
637684
638−Metaprogramming is the practice of writing code that manipulates other code at either compile-time or runtime. In Lisp, metaprogramming is a core feature of the language, and it allows developers to create programs that are incredibly powerful and flexible. Lisp's metaprogramming capabilities are primarily built on two features: macros and the consequent ability to manipulate the language's own syntax.
685+Metaprogramming is the practice of writing code that manipulates other code at either compile-time or runtime. In Lisp, metaprogramming is a core feature of the language, and it allows developers to create programs that are incredibly powerful and flexible. Lisp's metaprogramming capabilities are primarily built on two features: macros and syntax manipulation.
639686
640687Macros in Lisp are a way to define new language constructs that are more expressive and more powerful than those provided by the language itself. When a Lisp program is compiled or interpreted, macros are expanded into regular Lisp code, allowing the macro to generate new code based on its input arguments. Since Lisp code is represented as data, it can be manipulated using the same functions and operators used to manipulate other data structures.
641688
642689For instance, Lisp macros could allow you flexibility in expressing a common operation. Imagine you're working on a project that requires a lot of complex math calculations. Rather than writing out each calculation manually, you could define a macro that takes an expression in infix notation (e.g. `2 + 3 * 4`), and transforms it into a Lisp expression that can be evaluated directly. Thus you could compose math expressions in a more human-natural way without having to worry about details of Lisp syntax.
643690
644−Lisp can also manipulate its own syntax is through the use of reader macros. Reader macros are similar to regular macros, but they operate at the level of the Lisp reader, which is responsible for converting textual input into Lisp expressions. Reader macros can be used to extend the syntax of Lisp in powerful ways, allowing developers to define new syntax for specific types of data or operations. For example, imagine you're working on a project that requires parsing a lot of complex data files. Rather than writing a lot of custom parsing code, you could define a reader macro that takes a specific input format (e.g. JSON or YAML), and transforms it into a Lisp expression that can be directly manipulated by your code.
645−
646−(Hoon can accomplish something similar via parsing, but not at the level of the Hoon language input.)
647−
648−In Lisp, code is represented as lists of symbols and expressions, which means that the syntax of the language can be easily manipulated and transformed using standard Lisp functions.
691+Lisp can also manipulate its own syntax. This is sometimes done through the use of reader macros, which operate at the level of the Lisp reader, which is responsible for converting textual input into Lisp expressions. Reader macros can be used to extend the syntax of Lisp, allowing developers to define new conventions or domain-specific languages for specific types of data or operations. Beyond reader macros, Lisp can permit the developer to change the parser (and as long as the result is a Lisp expression, the interpreter or compiler will be fine with this). Top-level functions can be replaced or modified (“advised”). Symbol macros can change source code.
649692
650−Lisp's `'` quote and the `eval` statement allow single expressions to be deferred or evaluated at will, which is incredibly useful when dealing with symbols that may not be defined yet or in the composition of macros.
693+Lisp's `'` quote and the `eval` statement allow single expressions to be inhibited or evaluated at will, which is incredibly useful when dealing with symbols that may not be defined yet or in the composition of macros.
651694
652−In addition to macros and syntax manipulation, Lisp dialects typically provide a number of other features that make metaprogramming easier, such as the ability to inspect and modify the runtime environment, and the ability to redefine functions and classes at runtime. Code reflection allows runtime creation of functions or macros (as at the REPL).
695+In addition to macros and syntax manipulation, Lisp dialects typically provide a number of other features that make metaprogramming easier, such as the ability to inspect and modify the runtime environment, and the ability to create or redefine functions and classes at runtime.
653696
654697### Metaprogramming in Hoon
655698
@@ -696,7 +739,7 @@ Hoon's focus on atoms, static typing, and symbolic expressions make it a highly
696739
697740Lisp has evolved greatly since John McCarthy's founding. Like Unix, a complicated family tree has finally settled down into a few strong contenders: Scheme, Common Lisp, Clojure, Racket.
698741
699−Lisp has tended to be fractious: as many have noted, and [Mark Tarver eloquently expressed](http://web.archive.org/web/20080803193859/http://www.lambdassociates.org/blog/bipolar.htm), the Lisp platform appeals to complete implementation of idiosyncratic vision. There's a looseness in the community's coherence as a result.
742+Lisp has tended to be fractious: as many have noted, and [Mark Tarver eloquently expressed](http://web.archive.org/web/20080803193859/http://www.lambdassociates.org/blog/bipolar.htm), the Lisp platform appeals to idiosyncratic visions for completist platforms. There's a looseness in the community's coherence as a result.
700743
701744For a few reasons, the Urbit community has managed to avoid such splintering (the [Urbit Classic joke](http://urbit-classic.org/) aside). With a single sponsoring organization, first Tlon Corporation and since 2022 the Urbit Foundation, to steward the ecosystem and a philosophical commitment to protocol-as-platform, Urbit should avoid partition into competing bazaars.
702745