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 forall
6 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
- 1: For Want of a Nail
- 2: The Five Whys
- 3: George Herbert
- 4: Last line is not a verbatim reproduction since the original poem contains an embelishment which is beyond the scope of this (silly) exercise
- 5: Logic Programming Red Cut
- 6: forall - SWI Prolog documentation