1 % Taxonomy stuff? Listing of all values given in their correct structure
    2 :-dynamic frame/3.
    3 frame(band, top, [has(songs)]).
    4     frame(electric, subclass_of(band), [has(bands, solo)]).
    5         frame(blues, subclass_of(electric), [popular(us, uk)]).
    6             frame(chicago, subclass_of(blues), [influences(deltablues)]).
    7                 frame(muddy, instance_of(chicago), [started('1941')]).
    8                 frame(elmore, instance_of(chicago), [started('1951')]).
    9             frame(delta, subclass_of(blues), [originated('1920s')]).
   10                 frame(robert, instance_of(delta), [songs('Kind Hearted Woman Blues')]).
   11         frame(punk, subclass_of(electric), [popular('1970s')]).
   12             frame(british, subclass_of(punk), [notable(sexpistols)]).
   13                 frame(theclash, instance_of(british), [songs('London Calling')]).
   14             frame(new_york, subclass_of(punk), [originis('CBGB Club')]).
   15                 frame(ramones, instance_of(punk), [songs('Blitzkrieg Bop')]).
   16     frame(acoustic, subclass_of(band), [has(bands, solo)]). 
   17         frame(rock, subclass_of(acoustic), [instruments([guitar, drums, stringbass])]).
   18             frame(soft, subclass_of(rock), [vocals(highpitch)]).
   19                 frame(nora, instance_of(soft), [influences(jazz)]).
   20                 frame(ry, instance_of(soft), [firstnoted('1960s')]).
   21             frame(hard, subclass_of(rock), [vocals(heavy)]).
   22                 frame(john, instance_of(hard), [songs('Sad To Belong')]).
   23                 frame(richard, instance_of(hard), [origin(unknown)]).
   24         frame(folk, subclass_of(acoustic), [instruments([violin, fiddle, viola, melodeon, piano, tenorguitar])]).
   25             frame(trad, subclass_of(folk), [madefor(fun)]).
   26                 frame(ewan, instance_of(trad), [songs('Dirty Old Town')]).
   27                 frame(eliza, instance_of(trad), [songs('Turpin Hero')]).
   28             frame(commercial, subclass_of(folk), [madefor(money)]).
   29                 frame(roger, instance_of(commercial), [songs('The Argonaut')]).
   30                 
   31 /* fadd/3 - should take the name of an object and the item to add. It will
   32 then need to modify the knowledge base to update the named frame (or produce
   33 an error message if no frame of this name exists) with the added detail.
   34 Finally it should list out the changed datastructure. */
   35 fadd(Target, Item, Content):-
   36     % Change Item, Content to Item(Content).
   37     NewContent =.. [Item,Content],
   38     % Get some info from the existing frame.
   39     frame(Target, Info, ExistingContent),
   40     % Add the new content to the existing list.
   41     append(ExistingContent, [NewContent], Result),
   42     % Delete the old frame
   43     retract(frame(Target, Info, ExistingContent)),
   44     % Add a new frame with the new content.
   45     assert(frame(Target, Info, Result)),
   46     % Report success
   47     write(Target),write(' frame has been added to. The frame now is:'),nl,
   48     write('frame('),write(Target),write(','),write(Info),write(','),write(Result),write(').').
   49 
   50 % Error predicate, requires no parameters.
   51 fadd(_, _, _):-
   52     % Reports failure.
   53     write('No frame found to add to.').
   54     
   55 /* fchange/3 - takes as its first argument a name of a frame and then as
   56 its second an item to change in the body of the frame and the third item
   57 its new value. If that item is not there to change then the frame should
   58 not be altered and an error message given back to the user.  If the item
   59 is found then it should be changed accordingly and finally it should list
   60 out this changed data structure. */
   61 fchange(Target, Item, Content):-
   62     /* Change Item to Item(_). Uses _ so that the Item will match regardless
   63     of the content. Providing the Item exists. */
   64     RemoveContent =.. [Item, _],
   65     % Get some info from the existing frame
   66     frame(Target, Info, ExistingContent),
   67     % Attempt to remove the given Item from the listing.
   68     delete(ExistingContent, RemoveContent, Result1),
   69     % If the resulting list is different from the original, then carry on.
   70     not(ExistingContent=Result1),
   71     % Change Item, Content to Item(Content).
   72     NewContent =.. [Item,Content],
   73     % Append the new content onto the resulting list form earlier.
   74     append([NewContent], Result1, Result2),
   75     % Delete the old frame.
   76     retract(frame(Target, Info, ExistingContent)),
   77     % Add a new frame with updated content list.
   78     assert(frame(Target, Info, Result2)),
   79     % Report success.
   80     write(Target),write(' frame has changed. The frame now is:'),nl,
   81     write('frame('),write(Target),write(','),write(Info),write(','),write(Result2),write(').').
   82 
   83 % Error predicate, requires no parameters.
   84 fchange(_, _, _):-
   85 % Reports failure.
   86     write('Could not find that item.').
   87     
   88 /* fremove/2 - should remove an item from the body of the frame, or give
   89 an error message if this item is not found. */
   90 fremove(Target, Item):-
   91     /* Change Item to Item(_). Uses _ so that the Item will match regardless
   92     of the content. Providing the Item exists. */
   93     RemoveContent =.. [Item, _],
   94     % Get some info from the existing frame.
   95     frame(Target, Info, ExistingContent),
   96     % Attempt to remove the given Item from the listing.
   97     delete(ExistingContent, RemoveContent, Result),
   98     % If the resulting list is different from the original, then carry on.
   99     not(ExistingContent=Result),
  100     % Delete the old frame.
  101     retract(frame(Target, Info, ExistingContent)),
  102     % Add a new frame with updated content list.
  103     assert(frame(Target, Info, Result)),
  104     % Report success.
  105     write(Target),write(' frame has had an item removed. The frame now is:'),nl,
  106     write('frame('),write(Target),write(','),write(Info),write(','),write(Result),write(').').
  107 
  108 % Error predicate, requires no parameters.
  109 fremove(_, _):-
  110     % Reports failure.
  111     write('Could not find that item.').
  112 
  113 % fdelete/1 - removes a leaf node only.
  114 fdelete(Target):-
  115     % Remove frame that matches target.
  116     retract(frame(Target, instance_of(_), _)),
  117     % Report success
  118     write('The instance of '),write(Target),write(' has now been deleted.').
  119 
  120 % Error predicate, to check if specified target exists but is a subclass.
  121 fdelete(Target):-
  122     % Check is target is a subclass.
  123     frame(Target, subclass_of(_), _),
  124     % Report failure.
  125     write('You cannot delete subclasses, only instances.').
  126 
  127 % Error predicate, requires no parameters.
  128 fdelete(_):-
  129     % Report failure.
  130     write('Instance not found.').
  131 
  132 /* fask/2 - asks if something is true about an instance or class object
  133 and if necessary performs inheritance to check super classes. */
  134 fask(Target, Item):-
  135     % Write out the starting point
  136     write(Target),write(' '),
  137     % Move onto fask/3 using an empty list as history.
  138     fask(Target, Item, []).
  139 
  140 /* fask/3 - checks to see if given target exists in history to prevent
  141 checking the same frames repeatedly in a loop. */
  142 fask(Target, _, History):-
  143     % Checks if given target is in history.
  144     member(Target, History),
  145     % Report error
  146     nl,write('Error: Loop detected.').
  147 
  148 % fask/3 run through - gets the current target's item list.
  149 fask(Target, Item, _):-
  150     % Get the item list from the target frame.
  151     frame(Target, _, ItemList),
  152     % Check if given item is in item list.
  153     member(Item, ItemList),
  154     % If it was found, write success message and exit fask/3.
  155     write('which '),write(Item).
  156 
  157 /* fask/3 run through - writes out current stage of class hierarchy
  158 traversal (relation and parent) and calls fask/3 with history updated
  159 and target set as the parent of the current frame. */
  160 fask(Target, Item, History):-
  161     % Get the targets relation with it's parent.
  162     frame(Target, Relation, _),
  163     % Split the relation into type and parent name.
  164     Relation=..[Type, Parent],
  165     % Write out the details.
  166     write(Type),write(' '),write(Parent),write(' '),
  167     % Append the current target to the history list and recurse fask/3.
  168     fask(Parent, Item, [Target|History]).
  169