From Fixed Points to Recursion

Recursion refers to self-referential code. Most people are familiar with recursion in the form of names that are used before their values are fully computed. The classic Fibonacci function can be used to illustrate this. As you can see, the definition of fib references itself.

fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)

The fix function in Haskell calculates the least fixed point of the function provided as argument, if it exists. From numerical analysis, you may recall a fixed point as a value at which the output remains unaltered no matter how many times you apply the function to it. In other words, the following statement is true for all f, for which the fix function can be computed:

f (fix f) = fix f

To use the fix function, we first need to a redefine fib as a function that can be supplied to it. We define a new variable f that represents the Fibonacci function, moving fib over to the right side.

let f = \fib -> \n -> if n < 2 then n else fib (n - 1) + fib (n - 2)

In plain English, you could read this as: given the Fibonacci function and a number, we can calculate the value as (a) the number itself if it is less than 2, or (b) the sum of the Fibonacci function applied to the previous two numbers respectively.

Notice that the definition above no longer uses recursion; it simply accepts fib and n as arguments, and calculates the result.

We now find the least fixed point for the Fibonacci function, and apply it to the desired input. For instance, to find the 11th Fibonacci number, we write:

import Data.Function (fix)
fix f 11

…and voila! it prints the result 89.

If you open up the source code of fix, this is how it is defined:

fix :: (a -> a) -> a
fix f = let x = f x in x

Again, in plain English, replace x with the supplied function f applied to (f applied to (f applied to (…))), then return x. You would think this would go into an infinite loop — and it does, if the function doesn’t converge — but it actually works! One of the advantages of a language with non-strict evaluation semantics like Haskell is the ability to work effectively with infinite regress.

Link to GitHub

That’s all for today, folks! 🖖

First Principles

Over the years, with inspiration from many sources, I have come up with a number of “first principles” or beliefs that guide me on a daily basis. I would like to share these with you here.

Update 2021-11-13: Grouped the principles by a call-to-action, and softened the language to eliminate absolutes.

Follow Your Dreams

1. Every day of life merits planning and purpose. Plan goals for every year, week, and day; work backwards from your goals.

2. Perfection is an enemy; it is driven by others’ perception of you. Embrace chaos; always operate in ‘draft’ mode.

Experience Life In Color

1. Life is about adding value, but it is also about adventure. Do things that scare you; don’t give other people the power to assign value to your work.

2. Emotions are messy, but they also add a lot to life. Let down your guard sooner; get out of your head and say what’s going on in your mind.

Don’t Get Stuck

1. Prioritizing means intentionally dropping the less important stuff. Identify things to drop and shut them down, even if it seems hard to let go.

2. Resistance to action is triggered by fear of failure. Avoid fear of failure by breaking down large goals into smaller, manageable, chunks.

3. Even the smallest chunk of progress keeps the momentum going. Start now to record and track your progress; don’t set the bar unrealistically high.

Do Stuff & Learn

1. Ideas are useless until they are experimentally tested. Build systems; record experimental results in your journal, learn from what you create.

2. Minimalism is your friend. Opt for simple, bare tools to get the job done; eschew sophisticated features.

3. Making mistakes presents opportunities to learn from them. Don’t stick to the known paths, explore new avenues, break stuff to see what happens.

Error Correction

A general technique in teaching an “artificial intelligence” is to feed it ground truth. This may come in many different forms, but the essential idea is this: you help the machine learn from its mistakes by giving it the “correct” answer, and some time to reflect on it.

“I want you to think about what you’ve done.”

This technique works equally well for us humans, as pithily explained in Daniel Coyle’s The Little Book of Talent:

Tip #22: Pay attention immediately after you make a mistake.

Coyle elaborates: “People who pay deeper attention to an error learn significantly more than those who ignore it. […] Develop the habit of attending to your errors right away. Don’t wince, don’t close your eyes; look straight at them and see what really happened, and ask yourself what you can do next to improve. Take mistakes seriously, but never personally.”

In the workplace, most technology companies have some form of retrospective that they codify into a process. At Amazon, this is called a ‘Correction Of Errors’, or ‘COE’ for short. When someone writes up a COE, they write down the nature and import of the error to the business, lessons learned as part of the incident and recovery, and actions to prevent future recurrence of the same class of problems. COEs leverage the 5 Whys process popularized by Toyota for going deeper into the problem and establishing root causes.

I’ve always been a proponent of writing COEs and learning from mistakes. It’s important to see the COE as an “engineering chisel” rather than a “managerial hammer”. As an engineer, writing COEs is a discipline you impose upon yourself to hone your craft.

“Now Look What You’ve Done!”

Some years ago, I proposed the idea of a ‘2 Hour COE’ that was well-received by engineers. It went like this: don’t hesitate to write COEs or think of them as ‘work’; dive right in and do it; don’t spend more than 2 hours to write up a single COE (keep it ugly); focus on root causes and learnings more than anything else; don’t create more than 1-3 action items (avoid creating new work for the team).

Last month, I accidentally missed a meeting with colleagues because my iOS Calendar app wasn’t accurately synced with the Microsoft Exchange server. Someone mentioned “5 Whys” jokingly, and I thought to myself: this isn’t the first time something like this has happened, and I sure keep complaining about it — what can I do to resolve root causes myself? Perhaps I should write up a COE!

Now, I love writing and I spent an hour in the morning with good coffee in hand injecting some subtle humor into the write-up. It was primarily a joke aimed at the guy who mentioned “5 Whys” (and gloriously accomplished the job, if I may say so myself), but last week, it became popular on blind and I got asked by more than one person: was I joking or serious? But can’t it be both? It turns out I did get something really useful out of it after all: I discovered an app called VMware Boxer that is fully supported for corporate email and does work flawlessly on iOS.

If you’re an Amazonian and have questions, join #ama-riyer on the corporate Slack workspace.