For Want of a Nail

I thought it would be fun to translate a poem, For Want of a Nail which has an interesting history1 which I came across while reading about The Five Whys2 technique. The version of the poem reproduced in this post is attributed to Welsh poet George Herbert3.

This is a poem which illustrates The Five Whys analysis to find the cause-and-effect relationship underlying a problem in an easy to remember form. Since the verses are quite simple, it is the kind of poem one can easily encode in Prolog as logical rules.

Poem

For want of a nail the shoe is lost;
For want of a shoe the horse is lost;
For want of a horse the rider is lost;
For want of a rider the battle is lost;
For want of a battle the kingdom is lost;
And all for the want of a horseshoe nail.

- George Herbert

In Prolog

To translate the poem for Prolog we can start with the facts in this poem. This story is very simple as it is only talking about a single incident type: loosing something because of something else. We can easily encode this information using a single predicate, itemlost_becauseof, as shown below.

Facts

itemlost_becauseof(shoe, nail).
itemlost_becauseof(horse, shoe).
itemlost_becauseof(rider, horse).
itemlost_becauseof(battle, rider).
itemlost_becauseof(kingdom, battle).

Predicates

write_poem(ItemLost) :-
    write_poem_aux(ItemLost);
    write_last_line(ItemLost).

write_poem_aux(ItemLost) :-
    itemlost_becauseof(Impacted, ItemLost),
    write_line(ItemLost, Impacted),
    write_poem_aux(Impacted).

write_line(Item, Impacted) :-
    write("For want of a "), write(Item), write(" a "), write(Impacted), write(" was lost;"), nl.

write_last_line(Item) :-
    write("And all for the want of a "), write(Item), write("."), nl.

To get the full poem4, we can ask Prolog - write_poem(nail). Nice thing about encoding the poem in Prolog is that we can get parts of the poem just as easily. For example, to see the impact of a lost horse - write_poem(horse), which will produce the following poem!

?- write_poem(horse).
For want of a horse a rider was lost;
For want of a rider a battle was lost;
For want of a battle a kingdom was lost;
And all for the want of a horse

Finding root cause

We can use following predicates for root cause analysis from the facts database.

loss_rootcause(ItemLost, Cause) :- 
    itemlost_becauseof(ItemLost, Z), loss_rootcause(Z, Cause), !.
loss_rootcause(ItemLost, Cause) :- 
    itemlost_becauseof(ItemLost, Cause).

item_impacted(Cause, ItemLost) :-
    itemlost_becauseof(ItemLost, Cause).
item_impacted(Cause, ItemLost) :-
    itemlost_becauseof(ItemLost, X),
    item_impacted(Cause, X).

With the loss_rootcause predicate, we can check whether the bard was correct in contending that, ultimately, a lost horse-nail was responsible for the fall of the kingdom, and indeed that is the case, as Prolog confirms for the following query.

?- loss_rootcause(kingdom, RootCause).
RootCause = nail.

We are using a Red Cut5 in the definition of loss_rootcause predicate since we want Prolog to stop looking for alternatives if it cannot unify to end up with the root cause for a given failure situation. This cut basically makes Prolog find the first Domino which fell down to cause the cascading failures.

For impact analysis, we can also use forall6 predicate from Prolog built-ins, to get a list of all the items impacted by a given item.

?- findall(X, item_impacted(nail, X), NailImpacted).
NailImpacted = [shoe, horse, rider, battle, kingdom].

All code used for this post can be found here - For Want of a Nail.pl.

Footnote

Annotated names, such as the nail => horse-nail, can be written with the use of another predicate as follows.

annotated_name(nail,  horse-nail).
annotated_name(X,  X).

write_annotated(X) :-
    annotated_name(X, Annotated), write(Annotated).

Then we can modify the write_last_line as follows to get a more faithful reproduction of the poem.

write_last_line(Item) :-
    write("And all for the want of a "), write_annotated(Item), write("."), nl.

Annotations are a set of predicates which matches a given item to a more embellished version. For example, we can add an embelishment for the rider with annotated_name(rider, 'brave rider'). With the updated database, the last line of a poem starting with the rider would be - “And all for the want of a brave rider.”, and so on.

References