in reply to Re^5: (why to use logic programming)
in thread Easy Text Adventures in Perl

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.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re^7: (why to use logic programming)
by Anonymous Monk on Feb 15, 2005 at 09:25 UTC
    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.
    Actually, you don't. It translates pretty straightforward:
    $foreigner{abdul} = 1; $foreigner{marcus} = 1; $spouse{edward} = "sally"; $spouse{sally} = "edward"; $spouse{bill} = "hillary"; $spouse{hillary} = "bill"; $gross_income{hillary} = 100_000; $gross_income{edward} = 20_000; $gross_income{bill} = 30_000; $gross_income{marcus} = 49_999; $gross_income{mary} = 35_000; sub average_taxpayer {my $Person = @_ ? shift : $_; !$foreigner{$Person} and not ($spouse = $spouse{$Person} and $income1 = $gross_income{$spouse} and $income1 > 30_000) and $income2 = $gross_income{$Person} and $income2 < 50_000 }
    You might want to declare some variables to make it strict (that would be extra code). About the only extra code the Perl part has is 2 extra spouse declarations, as hashes aren't symmetric. How does Prolog know that the "spouse" relationship is symmetric?
    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:
    And in Perl:
    @avg_taxpayers = grep {average_taxpayer} keys %gross_income;
    Now, I know about logic coding, and I'm aware of its merits. No need to convice me. But you've to come with a better example to show you need less code.