2

i am new to Prolog. I mabaged to understand how to do simple expert system, like

go :- hypothesize(Vehicle),
    write('I guess that the Vehicle is: '),
    write(Vehicle), nl, undo.



hypothesize(car) :- car, !.
hypothesize(van) :- van,!.
hypothesize(bike) :- bike, !.
hypothesize(mini) :- mini, !.
hypothesize(tank) :-tank, !.
hypothesize(sau) :- sau, !.
hypothesize(excavator) :- excavator, !.
hypothesize(bulldozer) :- bulldozer, !.
hypothesize(rocket) :- rocket, !.
hypothesize(shuttle) :- shuttle , !.
hypothesize(destroyer) :- destroyer, !.
hypothesize(civil_plane) :- civil_plane, !.
hypothesize(unknown).

/* Vehicle identification rules */ 
sau :- grounder, 
        verify(has_gun),
        verify(long_fire).
tank :- grounder,
        verify(has_gun),
        verify(short_fire).
excavator :- grounder,
        verify(no_gun),
        verify(have_ladle).
bulldozer :- grounder,
        verify(no_gun),
        verify(no_ladle).
car :- grounder,
        verify(big_body),
        verify(for_passengers).
van :- grounder,
        verify(big_body),
        verify(for_cargo).
bike :- grounder,
        verify(small_body),
        verify(two_wheels).
mini :- grounder,
        verify(small_body),
        verify(four_wheels).

rocket :- flying,
        verify(cosmos_flying),
        verify(can_return).
shuttle :- flying,
        verify(cosmos_flying),
        verify(cant_return).
destroyer :- flying,
        verify(air_flying),
        verify(warmade).
civil_plane :- flying,
        verify(air_flying),
        verify(civil).




/* classification rules */ 
grounder :- verify(has_wheels), !.
grounder :- verify(have_engine).

flying :- verify(has_wings), !.
flying :- verify(has_jets).

/* how to ask questions */ 
ask(Question) :- 
    write('Does the vehicle have the following attribute: '), 
    write(Question), write('? '), 
     read(Response), nl, 
     ( (Response == yes ; Response == y) 
     -> assert(yes(Question)) ; 
     assert(no(Question)), fail). 
:- dynamic yes/1,no/1. 
/* How to verify something */ 
verify(S) :- (yes(S) -> true ; (no(S) -> fail ; ask(S))). 
/* undo all yes/no assertions */ 
undo :- retract(yes(_)),fail. 
undo :- retract(no(_)),fail. 
undo. 

And this is good, but the question is - how to do "back" output, like, i will type "tank" in prolog window, and he will give all the parts this tanks consist - like, gun - yes, short rifle - yes, wings - no, e.t.c

Is it possible to do in expert system like this, or i have to do another programm?

Thank you for your reply

repeat
  • 18,496
  • 4
  • 54
  • 166
Senso Hakai
  • 141
  • 1
  • 2
  • 13
  • Please work on the aspect of code layout in your question. This would make it a lot easier for anyone who is willing to help => get more & better answers! – repeat Dec 01 '15 at 02:51

1 Answers1

2

Because your clauses are simple, I think you could do it using clause/2 like this:

?- clause(grounder, X).
X =  (verify(has_wheels), !) ;
X = verify(have_engine).

This is going to look something like this:

part(Vehicle, Part) :-
    clause(Vehicle, Body),
    part_of_body(Body, Part).
part_of_body(verify(Part), Part).
part_of_body(X, Part) :-
    atom(X), X \= '!', part(X, Part).
part_of_body((X,Y), Part) :-
      part_of_body(X, Part)
    ; part_of_body(Y, Part).

This is a little bit of a meta-interpreter. clause/2 allows you to inspect Prolog's rules programmatically. It's a reflection mechanism. clause(Head, Body) unifies Head with the name of the rule and Body with its body—in other words, Head :- Body. So when we say clause(tank, Body), we get back:

Body =  (grounder, verify(has_gun), verify(short_fire)).

Decomposing this is somewhat taxing; after all, you have to traverse as much of Prolog itself as you use in your rules. But that's what the rest of the code does. First, we fetch the clause in part/2: note that the type I expect in for Part is that of a vehicle type atom. Once we fetch the clause we hand it off to part_of_body to decompose Prolog's structure.

From here, a base case would be something like verify(has_gun), which seems to include the piece you're interested in (has_gun) and that's what the rule part_of_body(verify(Part), Part) says.

The recursive cases are the ones that handle the rest of the structure, so for instance, if I see an atom such as grounder, I recursively look up those parts, which is what part_of_body(X, Part) does. I'm not thrilled about having to test specifically for ! but there is a weakness in my approach there which I haven't fixed yet.

The main recursive case is the one that handles conjunctions: (X,Y). Here I just say, find some parts in the first part of the conjunction and then try the second.

?- part(tank, Part).
Part = has_wheels ;
Part = have_engine ;
Part = has_gun ;
Part = short_fire.

So this database can be worked backwards, it just isn't particularly convenient. :) A better data model would go a long way toward improving this situation.

Daniel Lyons
  • 22,421
  • 2
  • 50
  • 77
  • 2
    s(X) for suggesting a return to the modeling phase/stage! Quoting from "The five orders of ignorance" (cf. http://www-plan.cs.colorado.edu/diwan/3308-07/p17-armour.pdf ): *Unless great care is taken to remove all traces of the “unknowledge” from the code, some legacy will remain. That is, the program will be contaminated by the foot-prints of the “unknowledge."* In that sense we should recommend going back to the start *a lot more often*! – repeat Dec 01 '15 at 02:49
  • @repeat I have never seen this paper before but wow! What a revelation! :D – Daniel Lyons Dec 01 '15 at 07:20
  • I am serious! Yes please. :) – Daniel Lyons Dec 01 '15 at 14:13
  • "Speed of iteration [...] beats quality of iteration." cf. http://blog.codinghorror.com/boyds-law-of-iteration/ – repeat Dec 01 '15 at 14:26
  • A classic 2D partitioning method: https://en.wikipedia.org/wiki/Time_management#The_Eisenhower_Method . In particular, consider https://en.wikipedia.org/wiki/There_are_known_knowns ... "Mr R., Sir, what about the fourth square?" critics might say. LMFAO – repeat Dec 01 '15 at 14:29