Monthly Archives: June 2026

Energy Explained For Idiots Like Me

“Energy is a very subtle concept. It is very, very difficult to get right.”

– Richard Feynman

If you’re like me, you probably went through a few physics classes at a fancy, prestigeous university, and left the class while thinking “Huh?” In my experience, physics teachers aren’t good at teaching physics (even though they should be) and no place is that better demonstrated than in how they teach energy.

We’re told in physics class that “Energy is the ability to do work.” and that, in physics, “work is a force done over a distance so long as the force is perpendicular to the distance. If the force and the distance are in opposite directions the work is negative, and if they’re in the same direction the work is positive.”

You might even be able to solve a few homework problems using conservation of energy as a tool, but what is it exactly? What’s the context here? Why are we multiplying forces by distances?

“Teach principles, not formulas.”

-Richard Feynman.

Let’s start with the beginning. At the beginning of the industrial revolution engineers were making many machines for doing things. Some of those machines were for lifting objects. Engineers wanted a way to know how much coal they had to burn to get the machine to lift a given object by a given distance off the ground.

If you want to lift an elephant with a forklift one meter off the ground, how much fuel do you need? At the time nobody knew how to calculate that so it was all guesswork. One day they noticed something. Take the distance you’re lifting the elephant, multiply it by the weight of the elephant, and the result is proportional to how much coal you need.

If you want to lift two elephants you’ll need twice as much coal to be burned. If you want to lift one elephant two meters off the ground you’ll need twice as much coal for that as well.

Work was discovered by engineers, not physicists. If we look at it from a theoretical perspective, we see forces and displacements as vectors. Vectors can be scaled by a scalar. So if we multiply force by time we get the momentum of the object for the amount of time the force was applied to it.

If we take the dot product of two vectors (force and displacement) we get work exactly. The positive and negative sign are taken care of for us by using the dot product, and so is taking the component of the force that is perpendicular to the distance.

Why are we doing this? Well, as engineers we need to know how much coal we need, sure, but there is another reason. The ability to do work is conserved. Ability means it’s something that can happen. More energy means more work that can be done. Energy is a cheat code for physics.

Energy is not a real thing. It’s an abstraction. Feynman described it as a “book-keeping system of physics”. Basically, what you do is you take every object in a system and find the kinetic energy of each object (one half of it’s mass multiplied by the dot product of it’s velocity multiplied by it’s velocity) and add it to the total potential energy in the system (take the forces between every pair of objects and multiply that force by the distance between them) and that’s how much work CAN happen.

It’s a common misconception that energy and matter are the same thing. They’re not. What Einstein proved is that giving an object more energy increases it’s mass, but that’s special relativity and we’re talking about classical physics.

Imagine a bowling ball going down the lane. The amount of kinetic energy it has is half it’s mass times it’s speed squared. That’s how much you could lift an elephant by if that ball hit a machine that turns the motion of bowling balls into lifting force. The height you could lift an elephant is the kinetic energy from it divided by the weight of the elephant.

Before the bowling ball was thrown it was higher off the ground, and a force was applied to it by the person throwing it forward. The force that threw it forward, the distance that forces was applied for, and the height difference between when it’s on the ground and when it’s in the air all determine how much you can lift an elephant from our elephant lifting machine.

“Things are made of stuff.”

– Bill Nye

Of course, things are made of smaller things. That bowling ball is made of atoms, and those atoms are made of smaller particles. For now, let’s pretend that the atoms are as small as the particles get. When the bowling ball is heading down the lane, the atoms aren’t all perfectly aligned in their motion, nor are they perfectly aligned in their speed. Sometimes one atom in the front might be moving forward slower than the rest for a brief moment. From the perspective of an observer moving alongside the ball such an atom seems to be moving away from the pins.

Some of the atoms will be moving forward faster than the rest of the ball. How much energy is there really in this system? Add up all the kinetic and potential energies and that’s how much elephant you can lift, right? Not quite. The bowling ball is a macroscopic object, the jiggling inside of macroscopic objects is heat energy. When that bowling ball hit the ground, it deformed a tiny bit (as all objects do when they hit the ground) and that deformation lead to a tiny bit of heat in it.

This brings us to something important: even though “energy is conserved” in theoretical physics, in the real world it basically isn’t. In engineering energy gets turned into heat. There are no elephant lifting machines that are 100% efficient. The only thing with such efficiency is a heating coil meant to turn energy directly into heat.

Energy is our book keeping system. It’s what we use to simplify calculations precisely because it’s conserved. Part of the problem with how energy is taught is the lack of context and thought experiments. For example imagine a bowling ball hurtling through space when the magical force vector of theoretical physics applies itself to the bowling ball such that it slows down.

The distance the ball traveled as it was slowing down points in the opposite direction of the force vector so the work is negative meaning that the ball lost some energy. Where did the energy go? Nowhere. It’s not a real thing. In this case it went nowhere because magical force vectors don’t exist in the real world.

In the real world forces come in pairs. A force slowing down the bowling ball might just be speeding up another object so we say the “energy” has been transferred from one object to another, but it’s not a real thing. It’s just an abstraction to simplify calculations and, in fact, in Einstein’s theory of general relativity energy is no longer conserved (see Noether’s theorem for more on that).

When you climb up stairs, you’re pushing the world down slightly with each step, and the potential energy starts to go up. Gravity wants to pull you down, but you’re being lifted. The work done is negative. You’re exchanging chemical energy for gravitational potential energy. The energy is being drained from you, and stored in the height you are up off the ground. If the staircase magically vanishes then you fall down and the potential energy turns into kinetic energy. As your velocity increases so too does the rate at which energy gets converted.

Power is the rate at which energy gets transferred from one thing to another. It’s generally taught as a force times a velocity. How can that be? If there’s an unbalanced force then the velocity is changing. Of course, power doesn’t have to be constant like energy does, so the power changes as the magic force vector accelerates the object. If the force is balanced then that means either no forces are acting on the object, or the forces are perfectly balanced and pointing in opposite directions meaning that none of the objects motion is work. It’s all just kinetic energy.

This leads us to our last idea (for this blog post anyways). Entropy. If air pushes on an object in one direction and the exact same amount of air force is pushing on it in the opposite direction, now work is done. The air molecules have kinetic energy, but the object isn’t. This will be the state of the universe at the end. As energy gets used some of it is turned into heat. There’s no such thing as a 100% efficient process (except for perhaps heaters) and there never will be.

Thermal energy tends to go from height temperature to low temperature. This is both a good thing and bad thing. It’s good because we can exploit this. Just like how you can take advantage of falling water at a hydroelectric damn to get electrical energy, so too you can get energy from the heat moving from hot to cold, and like with electric damns the greater the difference in energy the more efficient you can be, but you can’t be 100% efficient.

Water passing by the generator can’t just stop completely and vanish from existence. It has to move out of the way so more water can pass by the generator, but to do that it has to have at least some kinetic energy. You can’t steal ALL of it’s energy.

Similarly, heat moves from hot to cold, but we can’t capture all the heat. The temperature of things will try to even out. That’s what entropy is. Entropy is how evenly distributed energy is in the universe. It’s the energy that was lost from the macroscopic world into the world of fundamental particles.

Energy can be moved from cold to hot artificially (like what air conditioners, and refrigerators do), but to do that requires energy from the generator, and the way the math works out the entropy of the refrigerator/generator system will have increased.

Eventually all macroscopic energy will be gone and time will stop. Does time exist by itself? Some say no. Some say that time only exists between events. In a universe where nothing happens (one with full entropy) time would have no meaning. We call the idea that time only exists between events relative time, and the idea that time exists by itself absolute time. When physicists talk about time they’re generally talking about relative time.

Imagine that everything in the entire universe froze perfectly in place and some absolute amount of time passed. It could be a large absolute amount of time or a little. It could be nanoseconds or trillions of years, when events start happening again we humans would have no way of knowing how much absolute time had passed. In fact, we wouldn’t even know that it had happened at all. The only way to measure time is too measure the number of time some event happens that should (in theory) have a constant absolute time between each tick.

When the universe ends nothing at our macroscopic scale will be able to move at all. We can say that energy is, informally, defined as the ability to do stuff, and that work is the stuff happening. No more macroscopic work means no more events which means time has stopped. Of course things will continue happening to fundamental particles, but that’s not very helpful to us (note: time won’t every completely stop. It will just slow down more and more because entropy can only increase and it can never reach 100%. It can only get closer and closer).

I hope this helped at least somewhat. I’m a bit of a lazy writer, so there are some thought experiments that I’ll leave up to the reader, but hopefully this can help get you started. If you have any questions just ask them in the comments and I’ll try to answer them when I see them.

Do You Have What It Takes To Understand Monads? Yes, You Do.

Do you have what it takes to understand Haskell’s monads? I think you do. I recently learned how they work, and unlike most people who add way too much rigor to their sterile explanations, I can explain it. In a previous blog post I said that Haskell monads are a data kind that let us write functions that can work on any data type that contains another type. Since then I’ve learned there’s way more to what they can do, and that that’s not actually what they were meant for.

The point of monads is that they let you chain together operations. Let’s look at an example. Say that you wrote some code in Haskell that’s part of a program which uses a configuration file. The program starts up, reads the config file, calls up the first function and passes a huge number of arguments to the function.

That huge number of arguments would be mostly the configuration variables from the file. We would write many functions for the program that need to access the config data so each of them gets a huge number of arguments, and then when we add a new config variable we need to redo a lot of code for each major function.

Obviously that’s a terrible way to do things. So we might instead create a data structure that contains all the config variables and pass that to every function like so:

data Conf = Conf { maxTemp :: Double,
randSeed :: Int,
maxNumPlayers :: Int,
screenWidth :: Int,
screenHeight :: Int,
aiModelFileNameForAutoModeration :: String} deriving(Show)

fn :: Conf -> Int -> Result
fn cnf@(Conf { randSeed = stupidShitWeNeed }) someKindOfInt = do
    let res1 = fn2 cnf 5
        res2 = importantCode cnf stupidShitWeNeed
        res3 = moreImportantCode cnf someKindOfInt
    res1 ++ res2 ++ res3

 

This looks better than our ugly solution from before, but it can look even nicer. Meet the reader monad. The reader monad lets you write functions which can query stuff from your data structure without having to pass the structure as an argument. Like so:


import Control.Monad.Reader

fn :: Int -> Reader Conf Result
fn someKindOfInt = do
    stupidShitWeNeed <- reader randSeed
    res1 <- fn2 5
    res2 <- importantCode stupidShitWeNeed
    res3 <- moreImportantCode someKindOfInt
    return (res1 ++ res2 ++ res3)

That sounds nice and all, but how does it work? Well the secret is Haskell’s do notation. When code is in a do block like so:


fn a b = do
    let f = fn2 a
    f2 <- fn3 f b
    return f2

The do block automagically chains the operations together. Monads are a data kind that only need a few methods and one of them is the >>= method. That method takes in something of that particular monad kind, applies a function to it as the second argument which will be applied to what’s in the monad, and then returns the result wrapped in a monad. So, in our example above, f is passed as a function to the >>= method as the second argument, and the first argument is f2 (do notation can lead to rearranging the order of things), and then the result is returned wrapped in a monad since >>= always returns a result in a monad.

But wait! There’s more! Consider the following code:

 



fn1 :: Int -> Int -> Either String Int
fn1 a b = do
    if b == 0
    then
        Left "You can't divide by zero!"
    else
        Right (div a b)

fn2 :: Int -> Int -> Int -> Either String (Int, Int, Int)
fn2 x y z = do
    let dx = x * x
        dy = y * y
        dz = z * z
        r = sqrt (dx + dy + dz)
        retx = fn1 dx r
        rety = fn1 dy r
        retz = fn1 dz r
....


I couldn’t even bring myself to finish that function because it was quickly becoming so ugly. Here we have code that awkwardly tries to deal with errors. Every major function in this hypothetical program can call up another function and get an Either type that contains either an error message or the return result. As you can imagine, having to constantly check the return result for errors and throw those errors up the stack gets annoying. So let’s do it like this:

 


import Control.Monad.Except

fn1 :: Int -> Int -> Except String Int
fn1 a b | b == 0 = throwError "You can't divide by zero!" 
fn1 a b = return (div a b)

fn2 :: Int -> Int -> Int -> Except String (Int, Int, Int)
fn2 x y z = do
    let dx = x * x
        dy = y * y
        dz = z * z
        r = sqrt (dx + dy + dz)
    retx <- fn1 x r
    rety <- fn1 y r
    retz <- fn1 z r
    return (retx, rety, retz)

This one was much easier. I was even able to finish it.

Where we use the Except monad we chain together operations and each of them can throw up an error message. When we run our main code with the runExcept function, fn2 will return either the error message or the return result. We can use the runExcept function at the top level of our code (the part that runs the main part of code that has no side effects). This means that we don’t have to pollute our arguments, return types, and code with a bunch of crap for transferring things along our pipeline.

There are many different monads that we can use. Here are some of my favorite:

  • The except monad for errors
  • The state monad for tracking the state of the program
  • The reader monad for storing config information
  • The logic monad for backtracking (Yes, like the kind prolog does, albeit a bit more awkardly)
  • The par monad for launching computations that can be done in parallel
  • The parsec monad from megaparsec for parsing things.

And many more. You can also combine them using monad transformers so you can have state, config files, parallelism, parsing, errors and anything else like this:

 



import Control.Monad.State
import Control.Monad.Reader

data St = St { players :: [Player], deadNPCs :: [NPC], aliveNPCs :: [NPC], sleepingNPCs :: [NPC], npcsWithSleepApnea :: [NPC]}

data Conf = Conf { maxNumPlayers :: Int, mapName :: String, mapData :: GameMap, minNumRandomBansPerHour :: Int}

type Mon = StateT St (Reader Conf) 

runner :: Mon a -> Conf -> St -> a
runner a cnf st = let (ret, _) = runState a in (runReader cnf ret)

I used to be afraid of monads because I didn’t understand them and I thought that when you put data into a monad you can’t get it back out, but really monads are simple. They’re generally containers that hide away ugly repetitive code, and the vast majority of them will let you extract your data from them.