Your example shows why logic programming beats imperative programming hands down (in this particular case). Let's flesh out my example. For the sake of simplicity, we'll just say average taxpayers are not foreigners, their spouses (if any) make less than 30000 and their income is less than 50000.
foreigner(abdul).
foreigner(marcus).
spouse(edward, sally).
spouse(bill, hillary).
gross_income(hillary, 100000).
gross_income(edward, 20000).
gross_income(bill, 30000).
gross_income(marcus, 49999).
gross_income(mary, 35000).
average_taxpayer(Person) :-
not(foreigner(Person)),
not((
spouse(Person, Spouse),
gross_income(Spouse, Income1),
Income1 > 30000
)),
gross_income(Person, Income2),
Income2 < 50000.
So now it's trivial to find out if "marcus" is an average taxpayer (no) or if mary is (yes). You'd have to write a bit more Perl code than I would have to write Prolog code. However, this is the kicker. What if I want a list of all average taxpayers? Well, I know you have to have a gross income to be an average tax payer, so I issue the following query:
gross_income(Person,_), average_taxpayer(Person).
That will tell me that edward and mary are average taxpayers. I didn't have to write any extra code to do that. Logic programs can infer the answer. Perl would have a hard time keeping up with that. In fact, one of the fascinating things about logic programs is that they can all be reused in a similar manner. With imperative programming, reuse means "don't duplicate code." With logic programming, reuse means that, but it also means "use the same code to answer related but different questions."
One thing to keep in mind about logic programming is that you're not looking at function calls. You're looking at relationship definitions and you don't have to write any extra code to express them.
|