home *** CD-ROM | disk | FTP | other *** search
- % Complete Prolog listing of knowledge interpreter/ compiler
- % Tim Menzies, 1988
-
- :- op(995, xfx, if).
- :- op(985, xfx, then).
- :- op(975, xfy, or).
- :- op(950, xfy, and).
- :- op(925, fx, not).
- :- op(900, fx, mention).
- :- op(900, xfx, :=).
- :- op(150, xfx, are).
- :- op(125, xfy, of).
- :- op(100, xfx, from).
- :- op( 50, xfx, be).
- :- op( 50, xfx, #).
-
- dd( calf, % data dictionary for the calf database.
- [cname, pen], % the key for this database are the two
- % fields "cname" and "pen". The actual
- % fields are :
- [cname, % calf name
- col, % colour
- tbid, % tuberculois test ID number
- pen, % pen number
- yob, % year of birth
- mood, % temperament
- sex, % sex
- balls]). % castrated?
-
- calf( daisy, brown, 456, 7, 1987, sweet, female, no).
- calf( ivy, red, 546, 8, 1988, aloof, female, no).
- calf( ben, brown, 465, 9, 1986, nasty, male, yes).
- calf( rover, grey, 701, 10, 1985, sweet, male, no).
-
- raw(( known(age,AGE),
- known(torso,TORSO),
- known(this_year,NOW),
- bagof(AGE1,
- (calf(_,_,_,_,YOB,_,_,_),
- AGE1 is NOW-YOB),
- LIST),
- maximum(LIST,MAX),
- (AGE / (TORSO/2 * 3.14159) + 7) > MAX)).
-
- % If "known" can't find a certain fact, it asks the user for the fact,
- % then stores the fact for later use.
-
- known(X,Y) :- fact(X,Y) ,!.
- known(X,Y) :-
- ask(["Enter a value for [",X,"] : "],Y),
- assert(fact(X,Y)).
-
- maximum([H],H).
- maximum([H|T],MAX) :-
- maximum(T,TEMP),
- (TEMP > H -> MAX is TEMP | MAX is H).
-
- rad(DIAM,X) :- X is DIAM/(2 * 3.14159).
- maxof(X,Y) :- bagof(Y,X,L), maximum(L,Y).
-
- :- op(900,xfx,if), op(850,xfx,then), op(800,xfy,and).
- X and Y :- X,Y.
-
- rule1
- if known(age,AGE) and
- known(this_year,NOW) and
- maxof( (calf(_,_,_,_,YOB,_,_,_) and
- MAX is NOW - YOB),
- MAX) and
- known(torso,TORSO) and
- rad(TORSO,RADIUS) and
- (AGE / RADIUS + 7) > MAX
- then print("significant!").
-
- rule2
- if age / radius of torso + 7 > max of age of calf
- then mention "significant!".
-
- rule3
- if age / radius of torso + 7 > eldest_age of calf
- then mention "significant!".
-
- user_knows(age).
- user_knows(torso).
- user_knows(this_year).
-
- pi(3.14159).
-
- X from Y be (Z,KEY) :- % # 1;
- call_list([X,Y,Z,KEY]). % use known selector for query.
- X from Y be (Z,ID) :- % # 2; clause # 1 failed,
- not(call_list([X,Y,_,_])), % and the selector doesn't exist,
- selector(X,Y,SELECTOR), % make the selector,
- assert(SELECTOR), % assert it,
- call_list([X,Y,Z,ID]). % use asserted selector for query.
- X from Y be _ :- % # 3; clause # 2 failed,
- not(call_list([X,Y,_,_])), % the selector doesn't exist (i.e.
- % "selector" failed),
- print("Unknown db query [", X from Y,"]."),
- fail. % flag an error and fail.
-
- call_list(LIST) :- % construct a Prolog goal at runtime.
- GOAL =.. LIST,
- call(GOAL). % call the Prolog theorm prover on that GOAL.
- call(GOAL) :- GOAL. % NOTE: call is a built-in in some Prologs.
-
- selector(FIELD,DB, (FIELD(DB,VALUE,KEYS1) :- SELECTOR)) :-
- dd(DB,KEYS,FIELDS),
- length(FIELDS,ARITY), % built-in Prolog predicate
- functor(SELECTOR,DB,ARITY), % built-in Prolog predicate
- args([FIELD|KEYS],FIELDS,SELECTOR,[VALUE|KEYS1]).
-
- % args: extract the args that have the same position in CLAUSE as
- % the ELEMENTS in the LIST.
- args([],_,_,[]).
- args([ELEMENT|ELEMENTS],LIST,CLAUSE,[ARG|ARGS]) :-
- nth(ELEMENT,LIST,NTH),
- arg(NTH,CLAUSE,ARG), % built-in Prolog predicate
- args(ELEMENTS,LIST,CLAUSE,ARGS).
-
- % nth: the atom X is the NTH element within the passed LIST
- nth(X,[X|TAIL],1).
- nth(X,[Y|TAIL],N) :- nth(X,TAIL,TEMP), N is TEMP + 1.
-
- X from Y are Z :-
- are(X,Y,Z,SELECTOR),
- call(SELECTOR).
-
- are([], _, [], _).
- are([FIELD|FIELDS], DB, [VALUE|VALUES], SELECTOR) :-
- selector(FIELD,DB,(FIELD(DB,VALUE,ID) :- SELECTOR)),
- are(FIELDS,DB,VALUES,SELECTOR).
-
- radius(IN,OUT) :- calc(IN / (2 * pi), OUT).
- age(calf,OUT) :- calc(this_year - yob from calf,OUT).
- max(IN, OUT) :-
- bagof(OPTION, calc(IN,OPTION),OPTIONS),
- maximum(OPTIONS,OUT).
-
- % Pre-defined operators
- % :- op(700, xfx, [is, >=, >, =, /=, <, <=]).
- % :- op(500, yfx, [+, -]), op(500, fx, [+, -]).
- % :- op(400, yfx, [*, /]), op(350, xf, [^]), op(300, xfx, [mod]).
-
- :- op(125, xfy, of).
- :- op(100, xfx, from).
-
- calc(X,X) :- % # 1; X is a number.
- number(X).
- calc(X of Y,Z) :- % # 2; X is a procedure.
- call_list([X,Y,Z]).
- calc(X of Y,Z) :- % # 3; X is a undefined procedure
- not(clause(X(Y,Z),_)),
- print("Bad procedure call [",X of Y,"]."),
- fail.
- calc(X from Y,Z) :- % # 4; X is a database query.
- X from Y be (Z,_).
- calc(OP(X, Y), OUT) :- % # 5;
- maths(OP), % we have a mathematical calculation to do;
- calc(X,X1), % calculate the value of the calculation's
- calc(Y,Y1), % parameters;
- Z =.. [OP,X1,Y1],
- OUT is Z. % perform the calculation.
- calc(OP(X,Y),true) :- % # 6;
- logic(OP), % we have a logical comparision to do;
- calc(X,X1), %
- calc(Y,Y1), %
- call_list([OP,X1,Y1]).
- % if call_list fails, no value is bound (as per
- % standard Prolog).
- calc(X,Y) :- % # 7; data from the user.
- user_knows(X),
- known(X,Y).
- calc(X,Y) :- % # 8; a constant.
- atom(X),
- call_list([X,Y]).
-
- maths(infix is). maths(infix +). maths(infix -).
- maths(infix *). maths(infix /). maths(infix ^).
- maths(infix mod).
-
- logic(infix >=). logic(infix >). logic(infix =).
- logic(infix /=). logic(infix <). logic(infix <=).
-
- expand(X,Y,VAL) :-
- expand_calc(X,Y,VAL),
- !. % only do one parse
-
- expand_calc(X,_,_) :- % # 1 : catch variables before they
- var(X), % fall into the rest of the parse
- % and match inappropriately.
- print("ERROR: variable in expression").
- expand_calc(OP(X,Y), CODE,OUT) :- % # 2 : expand boolean expressions.
- logic(OP),
- expand(X,CODE1,OUT1),
- expand(Y,CODE2,OUT2),
- optimise(boolean,
- CODE1,CODE2,OP,OUT1,OUT2,OUT,
- CODE).
- expand_calc(OP(X,Y),CODE,OUT) :- % # 3 : expand arithmetic expressions.
- maths(OP),
- expand(X,CODE1,OUT1),
- expand(Y,CODE2,OUT2),
- optimise(arithmetic,
- CODE1,CODE2,OP,OUT1,OUT2,OUT,
- CODE).
-
- optimise(boolean, % # 1 : boolean expression,
- % all values known
- X = VAL1,Y = VAL2,OP,VAL1,VAL2,OUT,
- OUT = OUT) :-
- call_list([OP,VAL1,VAL2]) -> OUT = true | OUT = fail.
- optimise(boolean, % # 2 : boolean expression,
- % LHS known, RHS unknown
- VAL1 = VAL1,CODE2,OP,VAL1,OUT2,OUT,
- (CODE2,OP(VAL1,OUT2),OUT = true)).
- optimise(boolean, % # 3 : boolean expression,
- % LHS unknown, RHS known
- CODE1,VAL2 = VAL2,OP,OUT1,VAL2,OUT,
- (CODE1,OP(OUT1,VAL2),OUT = true)).
- optimise(boolean, % # 4 : boolean expression,
- % all unknown.
- CODE1,CODE2,OP,OUT1,OUT2,OUT,
- (CODE1,CODE2,OP(OUT1,OUT2),OUT = true)).
- optimise(arithmetic, % # 5 arithmetic expression,
- % all values known
- VAL1 = VAL1,VAL2 = VAL2,OP,VAL1,VAL2,OUT,
- OUT = OUT) :-
- CODE =.. [OP,VAL1,VAL2],
- OUT is CODE.
- optimise(arithmetic, % # 6 arithmetic expression,
- % LHS known, RHS unknown
- VAL1 = VAL1,CODE2,OP,VAL1,OUT2,OUT,
- (CODE2, OUT is CODE)) :-
- CODE =.. [OP,VAL1,OUT2].
- optimise(arithmetic, % # 7 arithmetic expression,
- % LHS unknown, RHS known
- CODE1,VAL2 = VAL2,OP,OUT1,VAL2,OUT,
- (CODE1, OUT is CODE)) :-
- CODE =.. [OP,OUT1,VAL2].
- optimise(arithmetic, % # 8 arithmetic expression,
- % all unknown.
- CODE1,CODE2,OP,OUT1,OUT2,OUT,
- (CODE1, CODE2, OUT is CODE)) :-
- CODE =.. [OP,OUT1,OUT2].
-
- max( IN, OUT,
- CODE = calc(IN,OPTION))
- :-
- bagof(OPTION,CODE,OPTIONS),
- maximum(OPTIONS,OUT).
-
- expand_calc(X of Y,CODE,OUT) :- % # 5 : calls to a
- % simple procedure.
- clause(X(Y,OUT),calc(THIS,OUT)),
- expand(THIS,CODE,OUT).
- expand_calc(X of Y,TAIL,OUT) :- % # 6 : calls to
- % a non-simple procedure.
- clause(X(Y,OUT,CODE = calc(THIS,VAR)),TAIL),
- expand(THIS,CODE,VAR).
- expand_calc(X from Y,SELECTOR,OUT) :- % # 7 : database queries,
- clause(X(Y,OUT,_),SELECTOR). % return a known selector
- expand_calc(X from Y,X(Y,OUT,_),OUT) :- % # 8 : database query,
- selector(X,Y,X(Y,OUT,_)). % generate and return a selector
- expand_calc(X,Y = Z,Y) :- % # 9 : constants
- atom(X),
- clause(X(Z),true).
- expand_calc(X,known(X,OUT),OUT) :- % # 10 : facts from the user.
- user_knows(X).
- expand_calc(X,Y = X,Y) :- % # 11 : numbers.
- number(X).
- expand_calc(X,_,_) :- % # 12 : none of the above-
- % invalid structure
- print("Compiler failure on [",X,"]."),
- fail. % flag an error and fail.
-