Inline Evaluation Adventure

12 Mar 2025

Inline evaluation has been around for a long time, but not every programmer has had the chance to use it. If you haven’t, this is an opportunity to try it.

To this end I’ve coded up a simple editor with some code examples. The following examples are all editable and executable, however no run button exists to execute them. You’ll use Control-r to RUN/EVALUATE pieces of code that you select from inside the editor panes below.

To see it in action, place your cursor immediately after the expression you want to evaluate in the editor below. Then, press Control-r (hold the Control key down while pressing the r key). For example, if you want to evaluate (+ 1 2 3), position the cursor after the closing parenthesis ) and then press Control-r. For brevity, we’ll be using ^r as shorthand for Control-r from now on.

1
;`-- Place cursor after 1 then hit ^r

"Gremlins are cuties!"
;                     `-- Place cursor after " then hit ^r

(+ 1 2 3)
;   `-- Place cursor after 1 then hit ^r

(+ 1 2 3)
;        `-- Place cursor after the ')' then hit ^r

(+ 1 (/ 8 2) (* 2 3) )
;           `-------`-` Place cursor after each ')' and then hit ^r

(+ 1
   (/ 8 2)
   (* 2 3))
;          `-- Place cursor after ')' and then hit ^r

 
;`-- Place cursor above this line and hit ^r

When you pressed ^r, the editor found the closest preceding complete expression and sent it it to a runtime session (REPL) for evaluation. The result then appeared right next to your code, exactly where you were already looking. No context change needed to see the code run.

You may have noticed that you can evaluate smaller parts of an expression, like (/ 8 2), just as easily as a full expression. You can also evaluate expressions that span multiple lines.

Lisp languages make it simple to write editor tools that can do this. It is trivial to write an editor plugin to detect an expression delimited by parenthesis.

Sometimes, when I’m uncertain about function names or behavior, instead of searching for them, I simply try evaluating them inline to see if they exist and if they behave the way I expect them to.

For example, I know I created a function that renders HTML into a div above the editor, but I can’t remember if it’s called show-html or display-html. Let’s evaluate both of the expressions below to see which one works:

;; was it show-html or display-html??
(show-html "<h1>It's in a DIV!</h1>")
;;                                   `-- ^r eval here

(display-html "<h1>It's in a DIV!</h1>")
;;                                      `-- ^r eval here

With inline evaluation, I can quickly discover which function is defined and if it does what I expect, all without leaving the editor or breaking my flow.

In the next example, let’s apply this same approach to discover what the look, move and reset functions do.

In all examples that follow, try evaluating each expression with ^r to see the results.

(look)

(move :east)

(reset)


Notice how the look function returns data describing your location in a text adventure game, while the move function lets you navigate through this virtual world.

This provides an opportunity to demonstrate how inline evaluation helps us build and refine code incrementally.

Evaluating (look) and (move :east) could work as a spartan interface to the game, but it would definitely be better to display this data using our display-html function. Right? Right??

Now if we examine the data that the look function returns we can see that it’s returning a hash map of some sort, with the keys :desc, :seen, :exit and so on. Each of these keys map to string descriptions of the state of the game.

Let’s work on formatting the data returned by look into some HTML that we can display.

;; First lets see what data is returned
(look)

;; I see a :desc key that holds a description 
(get (look) :desc)

;; OK we have a description let's put that into an HTML string
(str "<p>" (get (look) :desc) "</p>")

;; Now let's display that HTML
(display-html (str "<p>" (get (look) :desc) "</p>"))

Let’s improve our code by breaking out that paragraph tag into its own function:

;; Evaluate this to define the paragraph function
(defn p [content] 
  (str "<p>" content "</p>"))

;; now let's see how it works
(p "Hello")

(display-html (p (get (look) :desc)))

OK, now we are getting somewhere. But we also have to format the things that are :seen in the room:

(look)

;; Let's extract the :seen items
(get (look) :seen)

;; Add some context to the raw data
(str "You see: " (get (look) :seen))

;; put it in a paragraph
(p (str "You see: " (get (look) :seen)))

;; let's add the :desc and the :seen together
(str
  (p (get (look) :desc))
  (p (str "You see: " (get (look) :seen))))
 
;; then display it
(display-html
  (str
    (p (get (look) :desc))
    (p (str "You see: " (get (look) :seen)))))
		

So we’re building up some code to format the the data returned from the look function as HTML.

So let’s put this code in a function and start working on the function instead of just composing expressions.

;; so here's our initial format function
(defn look-html [data]
  (str
    (p (get data :desc))
    (p (str "You see: " (get data :seen)))))

;; let's see if it's working
(look-html (look))

;; and finally
(display-html (look-html (look)))

OK now we have a look-html function which we can re-use, but there is definitely room for improvement. If we look at the data that’s returned by the look function you can see that there is also an :img-path. Let’s use that to add more visual interest to our game display.

;; let's build up an expression to format the :img-path as 
;; an img tag
(get (look) :img-path)
(str "<img src='" (get (look) :img-path) "'/>")

;; let's insert the image tag into our look-html function
(defn look-html [data]
  (str
    ;; v-- added img here --v
    (str "<img src='" (get data :img-path) "'/>")
    (p (get data :desc))
    (p (str "You see: " (get data :seen)))))

;; let's see if it's working
(look-html (look))

;; and let's take a look!
(display-html (look-html (look)))

Not bad at all. OK, now we only have one more piece of information left to add to our look-html function. When you evaluate the (look) function you will notice an :exits entry which gives the player clues about which directions they can move from their current location.

I think we are at the point where you can add the :exits info to the look-html function.

;; here's the :exits data
(get (look) :exits)

;; Add the exits data to the function below:
(defn look-html [data]
  (str
    (str "<img src='" (get data :img-path) "'/>")
    (p (get data :desc))
    (p (str "You see: " (get data :seen)))
    (p (str "Exits: "    ))))

;; test it out here to see if it's working
(look-html (look))

;; and finally take a look!
(display-html (look-html (look)))

Do you want to play a game?

Now that we’ve built our look-html function, let’s use inline evaluation to explore the text adventure.

Below are several game interaction functions. Using the inline evaluation, evaluate each one to discover its purpose and effect on the game state. This demonstrates how inline evaluation serves as both a development and exploration tool.

(display-html (look-html (look)))
(move :east)

(stack)
(push :picture)
(peek)
(pop)

(unlock-function :_something?_)
(reset)

Don’t be afraid to enhance the UI. Here are some suggestions:

  • Create a looki function that combines our display-html and look-html functions: (display-html (look-html (look)))
  • Develop a movi function that calls move and then looki to show the new location
  • Extend your look-html function to display the (stack) information
  • your own images, there’s nothing stopping you from creating your own images and using those in the game

And end?

Thanks for taking the time to experience inline evaluation.

As programmers, we often fall into cognitive ruts that constrain our expectations of what the programming process can be. These mental ruts, in turn, limit the potential of what we create. I have observed decisions by language designers, programming architecture advocates, and tool builders that directly ignore or impede this type of interactivity—a situation I find genuinely unfortunate.

It’s hard to get people to try things outside their experience. It’s natural to resist unfamiliar ideas and dismiss them. Many who read this will likely respond by arguing that this kind of interactivity isn’t necessary or useful. However, in my humble opinion, that simply isn’t true.

Yes, these may be toy examples inside a toy editor, but this level of interactivity is very real. Clojure programmers—and others who use similar evaluation capabilities—apply this technique daily in professional settings, from data pipelines powering major retailers to the video streaming services you likely use yourself.

My argument isn’t that Clojure or Lisp is inherently superior to other languages, but that inline evaluation is incredibly valuable and deserves wider adoption across programming environments.

By experiencing it firsthand, you might be inspired to expect more from your programming languages and tools—or even create your own.