taxes.txt
来自「prolog开发工具」· 文本 代码 · 共 518 行 · 第 1/2 页
TXT
518 行
sum_lines(1040,['6a','6b','6c'],X).
The income calculations on form 1040 show how calculations
from different forms are tied together. In this case data is
drawn in from schedules B and C.
line(1040,7,'wages salaries etc',X) :-
wages(X).
line(1040,8,'interest income',X) :-
getl(b,3,X).
line(1040,13,'business profit or loss',X) :-
getl(c,31,X).
line(1040,22,'total income',X) :-
sum_lines(1040,[7,8,13], X).
The following rules from the adjusted income section of 1040
and the medical deductions for schedule A, show how straight
forwardly Prolog represents some confusing intertwined tax
code. The rule is, you can deduct the minimum of either: 25%
of your health insurance, or your income from a business from
taxable income. However, if you take a deduction on line
1040 - 25, then you must not include that amount in schedule
A.
line(1040,25,'health insurance',X) :-
health_insurance(A),
B is integer( 0.25 * A + 0.5 ),
getl(c,31,C),
minimum([B,C],X).
line(1040,30,'adjusted gross income',X) :-
line_dif(1040,22,25,X).
line(a,2,'medical fees',X) :-
medical_fees(A),
getl(1040,25,B),
X is A - B.
line(a,3,'7.5% of income',X) :-
getl(1040,31,A),
X is integer(0.075 * A + 0.5).
line(a,4,'total medical',X) :-
line_dif(a,2,3,X).
Here is the code that calls schedule A to get itemized
deductions, calculates the appropriate standard deduction,
and makes the right decision on which to use for the tax
form.
line(1040,'33a','itemized deductions',X) :-
getl(a,26,X).
line(1040,'33b','standard deduction',2540) :-
status(single).
line(1040,'33b','standard deduction',3760) :-
status(married_joint).
line(1040,'33b','standard deduction',1880) :-
status(married_separate).
line(1040,34,'less itemized deductions',X) :-
getl(1040,'33a',A),
getl(1040,'33b',B),
A > B,
line_dif(1040,31,'33a',X), !.
line(1040,34,'less standard deductions',X) :-
line_dif(1040,31,'33b',X).
The tax computation is done by another predicate which knows
how to build tax tables. It breaks income into a step
function in $50 increments and uses the formulas for the
midpoints of the steps. An excerpt is included here:
line(1040,37,'tax computation',X) :-
getl(1040,36,A),
compute_tax(A,X).
compute_tax(A,Tax) :- % adjust for tax table calc
B is integer(A / 50),
C is B * 50 + 25,
comput_tax(C,Tax).
comput_tax(A,Tax) :-
status(single),
rate_single(A,T), !,
Tax is integer(T + 0.5).
rate_single(A,T) :-
A =< 1800,
T is 0.11 * A.
rate_single(A,T) :-
A =< 16800,
T is 198 + 0.15 * (A - 1800).
Some forms require tabular information to be filled in on the
form. So far, the tax program does not handle this case. To
include it, certain lines have as their value a Prolog data
structure of the form table(TableName). TableName is the
name of a predicate in the data section which will write the
required table. The report predicate calls TableName when
it encounters this type of value.
For example, on schedule B - 2, you must list all of the
banks you earned interest from. The clause for line B-2 has
as its value table(int_inc_tab). This means there is a
predicate int_inc_tab in the database which displays the
banks and interest.
line(b,2,'interest accounts',table(int_inc_tab)).
line(b,3,'total interest income',X) :-
getl(b,2,_),
interest_income(X).
The report predicate is modified to call a predicate
process to deal with the Value. If Value is a structure
of the form table(T), then the predicate T is called.
Otherwise the Value is printed as before.
report(Form) :-
nl,
write('----- '),write(Form),write(' -----'),nl,nl,
lin(Form,Line,Desc,Value),
process(Line,Desc,Value),
fail.
report(_).
process(Line,Desc,table(T)) :-
write(Line),
tabto(5),write(Desc),nl,
T, !.
process(Line,Desc,Amount) :-
write(Line),
tabto(5),write(Desc),
tabto(45),write(Amount),nl.
Next let's look at the data portion of the program. On the
fantasy form we saw how simple data such as wages and
withheld are stored in the data section. Let's look now at
the messy case of interest income. With the Prolog
database, the data need not just contain data, but can
contain rules as well.
Besides having to provide a table, interest income is further
complicated in Taxachusetts by the necessity of having to
distinguish between interest from Massachusetts banks and
non-Massachusetts banks. However, the tax form program is
unaware of the underlying complexity and simply goes to the
database for int_inc_tab and interest_income. It does not
know if these are simple facts, or more complex rules.
% ----- data for schedule b -----
interest_income(Z) :-
mass_interest_income(X),
non_mass_interest_inc(Y),
Z is X + Y.
int_inc_tab :-
get_int_inc(Account,Amount),
tabto(5),write(Account),write(':'),
tabto(40),write(Amount),nl,
fail.
int_inc_tab.
% ---
mass_interest_income(X) :-
bagof(A,T^int_inc(T,A),L),
list_sum(L,X).
non_mass_interest_inc(X) :-
bagof(A,T^non_mass_int_inc(T,A),L),
list_sum(L,X).
get_int_inc(Acc,Am) :- int_inc(Acc,Am).
get_int_inc(Acc,Am) :- non_mass_int_inc(Acc,Am).
int_inc('first bank',186).
int_inc('second bank',170).
int_inc('wife''s checking',79) :-
status(married_joint).
int_inc('wife''s savings',721) :-
status(married_joint).
non_mass_int_inc('other bank',812) :-
status(married_joint).
The bagof predicate is used to assemble the separate clauses
into a list. It is a built-in predicate of Prolog which
was used for this program, but most Prolog's have a similar
predicate, usually findall. (If not, Programming in Prolog
by Clocksin & Mellish has the code for writing your own.)
Notice how even the data can have rules associated with it.
Some of the int_inc clauses will be included only if the
filing status is married_joint.
It is useful in the data section to distinguish between those
predicates which are required by the tax form predicates, and
those which support other data predicates. This way there
are no errors when the data is replaced since it is clear
which data predicates need to have a value.
The data section is especially useful for keeping track of
business expenses. Again the data contains the rules for the
specific case. In my case I use 1/7 of my apartment for my
home business. This figure is built into the rules which
calculate the utility expense which winds up as a line item
on schedule C. For next year I simply need to plug in the
new values for the electric bills. This data could also have
been saved in the separate clause format used for interest
income if preferred.
utils(XX) :-
phone(A),
gas_total(B),
elec_total(C),
oil_total(D),
X is A + (B + C + D) / 7,
XX is integer(X + 0.5).
elec_total(X) :-
elec(L),
list_sum(L,X).
elec([30,59,42,22,34,30,40,34]).
Conclusions
Prolog's use of logic to express programming constructs is
exceptionally well suited to financial applications. This is
due to the fact that financial applications are made up of
rules for relating data. This is exactly the paradigm that
Prolog uses.
In the case of a tax program, the advantage is even more
significant. The tax law is made up of many logical (this
could be debated) rules. The rules are represented almost
verbatim in Prolog code.
One issue that must always be raised is performance. It
seems as if this year I had one of everything the IRS cares
about. As a result my program had to deal with seven
different forms. The tax computation on a
Macintosh SE was under two seconds.
There is an opportunity to utilize Prolog for developing
intelligent financial applications. In particular a
commercial tax program might also include various rules which
give advice above and beyond the IRS rules. That is, it
would become an integrated tax program and expert system.
In addition, the straight forward rule syntax of Prolog makes
for code which is very easy to modify from year to year. The
proliferation of Prolog's on various machines makes the code
reasonably easy to port from machine to machine. In short,
the vendor working with Prolog has a tremendous advantage
over vendor's working with more conventional languages.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?