I'm finding that in several kinds of projects ranging from spare-time amusements to serious work, LLMs have become useful to me by (1) engaging me in a conversation that elicits thoughts and ideas from me more quickly than I come up with them without the conversation, and (2) pointing me at where I can get answers to technical questions so that I get the research part of my work done more quickly.
Talking with other knowledgeable humans works just as well for the first thing, but suitable other humans are not as readily available all the time as an LLM, and suitably-chosen LLMs do a pretty good job of engaging whatever part of my brain or personality it is that is stimulated through conversation to think inventively.
For the second thing, LLMs can just answer most of the questions I ask, but I don't trust their answers for reasons that we all know very well, so instead I ask them to point me at technical sources as well, and that often gets me information more quickly than I would have by just starting from a relatively uninformed google search (though Google is getting better at doing the same job, too).
I've been experimenting with that from a slightly different angle: teaching Claude how to play and referee a pencil-and-paper RPG that I developed over about 20 years starting in the mid 1970s. Claude can't quite do it yet for reasons related to permanence and learning over time, but it can do surprisingly well up until it runs into those problems, and it's possible to help it past some obstacles.
The game is called "Explorers' Guild", or "xg" for short. It's easier for Claude to act as a player than a director (xg's version of a dungeon master or game master), again mainly because of permance and learning issues, but to the extent that I can help it past those issues it's also fairly good at acting as a director. It does require some pretty specific stuff in the system prompt to, for example, avoid confabulating stuff that doesn't fit the world or the scenario.
But to really build a version of xg on Claude it needs better ways to remember and improve what it has learned about playing the game, and what it has learned about a specific group of players in a specific scenario as it develops over time.
Besides programming, my hobbies are writing stories, writing and recording songs, drawing, and painting. None of them needs to cost anywhere near $3000. Any of them can cost as much as you want.
Take the music hobby as an example. I have several expensive guitars now, but in the first 20 years of that hobby I probably spent under $1000 on guitars and related gear the entire time.
I think the decline in UI quality is real, but I don't think the web takes all of the blame. The blame that it does take is due to a sort of mixed bag of advantages and disadvantages: web technologies make it quicker and easier to get something interactive on the screen, which is helpful in many ways. On the other hand, because it lowers the effort needed to build a UI, it encourages the building of low-effort UIs.
Other forces are to blame as well, though. In the 80s and 90s there were UI research labs in indistry that did structured testing of user interactions, measuring how well untutored users could accomplish assigned tasks with one UI design versus another, and there were UI-design teams that used the quantitative results of such tests to deign UIs that were demonstrably easier to learn and use.
I don't know whether anyone is doing this anymore, for reasons I'll metion below.
Designing for use is one thing. Designing for sales is another. For sales you want a UI to be visually appealing and approachable. You probably also want it to make the brand memorable.
For actual use you want to hit a different set of marks: you want it to be easy to learn. You want it to be easy to gradually discover and adopt more advanced features, and easy to adapt it to your preferred and developing workflow.
None of these qualities is something that you can notice in the first couple of minutes of interacting with a UI. They require extended use and familiarization before you even know whether they exist, much less how well designed they are.
I think that there has been a general movement away from design for use and toward a design for sales. I think that's perfectly understandable, but tragic. Understandable because if something doesn't sell then it doesn't matter what its features are. Tragic because optimizing for sales doesn't necessarily make a product better for use.
If a large company is making a utility cares, they'll have a ux person/s, sometimes part of a design team, to make sure things are usable.
But if you're really big, you could also test in production with ab testing. But as you said, the motivation tends to be to get people to click some button that creates revenue for the company. (subscribe, buy, click ad)
Somewhat related to this, the google aistudio interface was really pushing gdrive. I think they reduced it now, but in the beginning if you wanted to just upload a single file, you had to upload it to gdrive first and then use it.
There was also some annoying banner you couldn't remove above the prompt input that tried to get you to connect to gdrive.
Yes true. It's basically form over function and it's not just limited to Web UIs.
Windows 11, iOS7, iOS26 are just some example of non Web UIs, which focused first on optimizing for sales, i.e. making something look good without thinking about usability implications.
It's called aging. Just wait until the first time you head back down the hall from the living room to the bedroom to get the thing you forgot to bring with you, get distracted for a moment by a pet or family member, and then can't remember if you were going down the hall to the bedroom or the living room.
This is the half-page of code that Alan Kay famously described as "the Maxwell's equations of software."
Common Lisp and MACLISP before it and Lisp 1.5 before that worked by providing a running program that implements the functions given in that half page and applies them and their effects iteratively to their own environment.
In other words, the basic model is that Lisp is a running program that you modify interactively by feeding expressions to it one after another.
Common Lisp's model still works like that: when you give it a source file it reads one expression after another from the file, evaluating the expressions as it goes, and altering the running environment to reflect any changes that they make, such as adding new definitions, updating data structures, and so on.
The Lisp reads the next well-formed expression, converting it into Lisp data structures. It then evaluates the resulting data structure, yielding some number of values and updating the environment at the same time. (In Common Lisp even pure functions have side effects if evaluated by the read-eval-print loop because the standard defines a globally-accessible variable named * that contains the value returned by the most recently-evaluated expression).
Common Lisp's design reflects this basic model, and much of its standard library is concerned with making it convenient to work this way. The ANSI standard likewise reflects this basic model of computation, including features specifically designed to support this style of interactive programming.
The process of evaluation allows, but does not require, compilation. Common Lisp interpreters (usually called "evaluators") do exist, but most practical implementations provide compilers that compile each expression in order to evaluate it. Some implementations are "compiler only": that is, every expression is always compiled in order to be evaluated, whether it's in a source file or typed at a repl prompt.
To answer some of your specific questions more directly:
> is behavior when running a script in "interpreter" mode guaranteed to
> be the same as when running in "native compiled code"?
"Guaranteed" is a strong word. ANSI specifies the behavior, and it's generally the same whether code is interpreted or compiled. That may be hard to achieve for some expressions, but if you find an example of different behavior, that's most likely a bug in ANSI compliance.
(I should allow for the possibility that the ANSI spec has some corner somewhere that allows for a difference, but I can't think of any off the top of my head. Of course, the spec is large and my memory is imperfect.)
> At what point does the compiler create an intermediate representation?
Depends on what you mean. Under some interpretations and in some implementations there may not be an intermediate form.
The normal lifecycle of an evaluation is:
- read: ingest text and convert it to Lisp data
- macroexpand: rewrite any macro expressions in the data
- eval: use eval and apply on the data to yield some result values
- print: convert the result values to text in a standard format and print it to *standard-output*
You might regard the result of the read function as an intermediate form, but I would say that what read produces is Lisp source code. In my view, the original text is not Lisp source code; it's a serialization of Lisp source code. Read converts the text into Lisp source code.
ANSI does not specify in detail exactly what eval has to do in order to yield results. It specifies abstractly what each function, macro, and special form is supposed to produce, and what side effects they are supposed to have on the running environment, but the details of how the code is generated and executed are up to the implementation. An implementation can simply walk the source code interpreting forms and producing the required effects; or it can convert them to some intermediate form such as bytecode and then let a byecode interpreter do the evaluating; or it can compile them directly to native code that does the evaluating when executed. These are implementation details not specified by ANSI.
One detail that is specified by ANSI is the expansion of macros. Macros are expressions that look like function calls or special forms, but which are implemented by applying a macro-expander function to the expression to produce a new expression that is then given to the evaluator. Macros may be defined by the system or by the user. They are expanded after read and before eval. The spec goes into some detail about how this process is supposed to work and what features of the language affect it.
> Why does SBCL not use LLVM?
LLVM's first release was 2003. SBCL's first release was 1999. Moreover, SBCL is a fork of CMUCL, which was first released in 1980, though that was before Common Lisp existed. It was called SPICE Lisp at that time, and the compiler rewrite that would turn it into Common Lisp happened about five years later.
The point is that one important reason that SBCL doesn't use LLVM is that it's a large mature codebase that predates the existence of LLVM by about 23 years. I'm not saying it would be impossible to port SBCL onto LLVM, but if you did it would be so much changed that it wouldn't really be SBCL anymore. It would probably also be easier to just write a new Common Lisp on LLVM (which is what the CLASP project has done).
> At what point are #-starting words(read macros?) evaluated and
> how is that different from interpreting to compiling.
An expression that starts with "#" is, as you alluded to, a reader macro. What that means is that when the read function starts to read the expression it encounters the "#" and that triggers it to look up the next character in a table of special read functions. If it doesn't find anything it signals a READER-ERROR. If it does find something then it applies the found function to the input to read it.
For example, if you feed it "#'+" then it looks up the quote character in the table of reader macros and finds a function that converts the expression to "(function +)". When "(function +)" is evaluated it returns the function that is globally bound to the symbol named "+".
So the sequence is:
"#'+" -> READ -> reader macro -> EVAL (function +) -> return the function bound to +
The details of what happens when a reader macro is executed depend on the reader macro bound to the specific dispatch character. A bunch of them are defined by the ANSI standard, but you're free to define your own, and it's up to you what those do. You just have to know that they will get called when the reader encounters "#" followed by whatever dispatch character you specify, and the output of the function will get passed to EVAL after you're done with it.
> How do I control the amount of optimization the compiler will do?
For example, (declare (optimize (speed 3)(safety 0)))
> Will the interpreter ever try to optimize?
The answer is implementation specific, and may not even make sense (for example if you are using a compiler-only implementation).
> Is garbage collection implementation-defined?
To a large extent, yes. The spec assumes that implementations provide automatic memory management, but I think the only directly-related feature specified by ANSI is the ROOM function. Every implementation I know of also has the GC function to trigger a collection, but I don't think it's in the spec. Different implementations also have different GC strategies, they may have more than one GC implementation, and they provide various different implementation-specific tools for inspecting and controlling GC behavior.
(Not answerer)
Slight clarification, because I had the same questions and the previous answer is already really good:
Rainer Joswig pointed out on StackOverflow that the evaluation order is as follows (even though CLHS seems non-explicit about this):
For a compiler, for every "lisp form" (see below):
1. Read time
2. Macroexpansion time
3. Compile time
4. Load time
5 Run time
Read time maps strings to symbolic expressions (lists and atoms). A Common Lisp form is a combination of lists and atoms that is valid Common Lisp, for example
(+ 1 2)
or
(format t "Hello World")
Note, that the following is a list but not valid code, a.k.a. a form:
("abc" 2 thingamagig)
Macroexpansion is when user-defined forms are turned into Lisp forms. This is how WITH-OPEN-FILE can be defined by a user or non-language-implementor. It cannot be a function, because it doesn’t really evaluate its first argument, the stream variable name (a symbol) and the arguments to open. Furthermore, it also cleans up the file handle with UNWIND-PROTECT.
Special forms and macros are "unlike function calls". The difference is, that special forms are provided by the language and macros can be provided by the user. The conditional "if" is a special form for this reason. Haskell sidesteps this particular problem by making "if" (and others) evaluate lazily. In lisp you can get a similar effect by wrapping stuff in lambdas with zero arguments as something called a thunk and funcalling that later.
Compile time takes lisp forms and turns them into "machine code" whatever that happens to be.
Compile time and load time are more easily understood when you look at parenscript. Valid parenscript forms are not always valid lisp forms and vice versa. But they are both symbolic expressions, so basically lisp lists of lists and atoms. Parenscript compiles to JavaScript strings. Those get loaded by the browser when it loads the HTML or JS page that contains the JavaScript strings. Then the browser runs that code.
Look at the differences between PS:defpsmacro and CL:defmacro and PS:defmacro+ps .
In Common Lisp:
Read macros are executed at read time. Macros are evaluated at macroexpansion time. Compiler macros are evaluated at compile time. Load-time-value is evaluated at load time. Funcall, apply, lambda, and technically eval are evaluated at run time.
The slight wrinkle is that eval applies all if these rules recursively. So LIST is a lisp run-time function, but you can also call it to create the output in a DEFMACRO form. All run-time functions already defined can be used for all later forms (and strings) when they are being processed. Doug Hoyte called this "run-time at read-time" [1]. And by extensions it is also "run-time at macroexpansion time" and "run-time at compile time" and "run-time at load time" and "run-time at run time". (This last one is functions as first-class values and having access to a compiler and EVAL.)
LOAD-TIME-VALUE is executed at load time. Technically, the following top-level form is, too:
(Eval-when (:load-toplevel) …)
For ideas on read macros look at Doug Hoyte's [1] SHARP-DOUBLE-QUOTE #" and SHARP-GREATER-THAN #> .
And Larry Tesler, who was a particular champion of usability testing and important in the development of the Human Interface Group. Larry cared a lot about usability.
When I was at NeXT, Steve Jobs told me that if it was up to him, Apple would get rid of the Human Interface Group. (Steve was rather hostile to Larry.)
Later, when it was up to Steve, he did exactly what he said: he got rid of HIG.
I think it’s easier to sell visual design than it is to sell usability because people see visual design immediately, but it takes time and experience to see and understand usability (and some users never seem to consciously notice it at all).
I had no idea Steve Jobs felt that way about Larry Tesler. There were so many great UI experts at Apple, like Larry Tesler, Bruce Tognazzini, and Don Norman. While I love Mac OS X for its stability and its Unix support, I prefer the interface of the classic Mac OS, and it seemed to me that many third-party applications of the era were even more compliant with Apple’s human interface guidelines compared to later eras.
A dream desktop OS for me would be something with a classic Mac interface and with conformity to the Apple human interface guidelines of the 1990s, but with Lisp- or Smalltalk-like underpinnings to support component-based software. It would be the ultimate alternate universe Mac OS, the marriage of Smalltalk (with Lisp machine influence) with Macintosh innovations. Of course, there were many projects at Apple during the 80s and 90s that could’ve led to such a system.
Now that I’m a community college professor, I have more free time in the summer months for side projects...
Or perhaps they all leave traces, but all write to the same log? And when reconstructing memory from the log, each constructed consciousness experiences itself as singular?
Which one controls the body? There is a problem there. You can’t just have a bunch of disembodied consciousnesses. Well, maybe.. but that sounds kind of strange.
It’s a single narrative that controls the body is what I mean. If one consciousness says “I am Peter” then other consciousnesses would know that and be conflicted about, if they don’t call themselves that.
What I mean is that a single narrative “wins”, not a multitude. This has to be explained somehow.
How do you know there aren't several different consciousnesses that all think they are Peter?
How do you know they aren't just constructing whatever narrative they prefer to construct from the common pool of memory, ending up with what looks like a single narrative because the parts of the narrative come from the same pool and get written back to the same pool?
Perhaps each consciousness is just a process, like other bodily processes.
Perhaps a human being is less like a machine with a master control and more like an ecosystem of cooperating processes.
Of course, the consciousnesses like to claim to be in charge, but I don't see why I should take their word for it.
No matter how you twist it at some point two consciousnesses differentiate on some contradictory issue maybe not name, but surely they differ on some issue otherwise they wouldn’t be .. different consciousnesses. Life as a human moves and is narrated as a single story, not the story of a thousand processes.
If that were true I can call my heart a process, my liver, etc. They are in a way part of me but they do not just ex nihilo cohere into a single narrative. That is an active process and whatever does that is the only really interesting one (IMO). So I think there might be a bunch of processes, sub personalities maybe, but there remains the problem of integration. Whatever integrates is the one that really fascinates me.
Anyway, thanks for indulging me. It is hard to go into any depth in this medium. I think you have really interesting ideas. Have a nice weekend.
At some moments there has to be a singular decision taken, such as which of two possible options to take. In such a moment some particular consciousness makes the decision, if it’s a decision made by a consciousness (though consciousness takes credit for more decisions than it actually makes, I think).
But granting that point does not grant that there is a single consciousness that is always (or ever) in charge, and it does not grant that any specific consciousness is associated with any specific singular narrative.
We know, scientifically speaking, some things that call the idea of a single consciousness with a single narrative into question. We know, for example from psychology of testimony that the same person’s memory of the same events differs at different times, and that the act of remembering rewrites memories. We have reason to suspect that the brain attributes to conscious choice decisions that are made too quickly for sensory data to reach the brain (and which may therefore be made elsewhere in the nervous system, even though the brain claims to have made the choice after the fact).
And I know from personal experience that some phenomena that normally appear to be singular conscious experiences can devolve into something else under some circumstances. For example, I have experienced blindsight, in which I cannot see something but can nevertheless collect accurate information from it by pointing my eyes at it. I have also experienced being asleep and awake at the same time.
Experiences like these are hard to account for if I assume that my consciousness is singular and continuous and in charge, but not so hard to account for if I assume that it’s a useful illusion cobbled together by a network of cooperating processes that usually (but not always) work well together. For example, many people might claim that it’s nonsense to say that a person can be asleep and awake at the same time, but it’s nonsense only if asleep and awake are mutually exclusive states of a singular consciousness. If, on the other hand, they are two neurological processes that are normally coordinated so that they don’t occur at the same time (because it’s less than useful for them to do so), then it’s not nonsense to observe that under unusual circumstances that coordination might be disrupted. Similarly, if seeing something is one process and consciously experiencing seeing it is a different process—normally, but not necessarily coordinated—then blindsight is not so hard to account for.
Not to mention that it’s trivially easy to find examples of consciousness not being in charge of our behavior, although it likes to think that it is.
I suggest that the supposed singular consciousness, supposedly in charge, may be an illusion constructed by a system of mostly, but not perfectly, coordinated cooperating processes.
I was mikel@apple.com for about a decade. I never got misdirected mail, probably because there aren’t all that many people with the first name "Mikel." The only other one I personally know of is Mikel Bancroft, who works at Franz, inc.
Of course the dialects are not so densely distributed in North America, and English has only been evolving in the Americas for a few hundred years, but there are a bunch of dialects, and I find them super interesting.
My paternal grandparents were honest-to-goodness Ozark hillbillies who spoke Ozark Midlands (also called South Midlands), which is very close to, and sometimes conflated with, Appalachian English.
I'm in the Ozarks now and at least in the region where I live, this dialect seems to be disappearing. I still hear traces of it, but I don't think I've heard anyone really speaking it in years.
That's too bad. I love that dialect--perhaps because it was the language that my grandparents spoke.
If you're curious about it, you could listen to some of Terry Gross' interview with Ralph Stanley. He spoke Appalachian English, but it's indistinguishable to my ear from the language my grandparents spoke.
Talking with other knowledgeable humans works just as well for the first thing, but suitable other humans are not as readily available all the time as an LLM, and suitably-chosen LLMs do a pretty good job of engaging whatever part of my brain or personality it is that is stimulated through conversation to think inventively.
For the second thing, LLMs can just answer most of the questions I ask, but I don't trust their answers for reasons that we all know very well, so instead I ask them to point me at technical sources as well, and that often gets me information more quickly than I would have by just starting from a relatively uninformed google search (though Google is getting better at doing the same job, too).