home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / aijournl / 1986_11 / pfl.art < prev    next >
Text File  |  1986-10-06  |  23KB  |  662 lines

  1.  
  2. Understanding Frame Languages, Part II
  3.  
  4. "The Implementation of PFL"
  5.  
  6. by Tim Finin
  7.  
  8.  
  9. Knowledge representation is fundamental to AI. Over the past 25 
  10. years, many special purpose languages have been developed for 
  11. representing knowledge in AI systems. Frame-based representation 
  12. languages (FBRLs) form a class which has achieved wide 
  13. popularity. In part one of this article, we discussed the 
  14. concepts which underly frame-based represention languages and 
  15. introduced a particular language, PFL (Pedagogical Frame 
  16. Language). In part two we give a functional description of PFL, 
  17. discuss implementational issues and exhibit portions of the 
  18. Common Lisp code which implements PFL.
  19.  
  20. PFL is was written for pedagogical purposes - it does
  21. not attempt to be very powerful, expressive or
  22. efficient. Although PFL is quite simple (amounting to
  23. less than 250 lines of commented Common Lisp code) it
  24. is sufficiently powerful to support the
  25. representational needs of many AI applications. The
  26. purpose of PFL and this article is twofold: (1) to
  27. describe in the most concrete terms possible (e.g.
  28. code) some of the concepts and mechanisms which underly
  29. frame-based representation languages and (2) to
  30. demonstrate some of the features of Common Lisp in the
  31. context of a complete, useful program.
  32.  
  33.  
  34. A Functional Description of PFL
  35.  
  36. This section discusses PFL from a functional point of
  37. view. The dozen major functions are presented and
  38. briefly described. The primary PFL functions can be can
  39. be classified by their use into those used to create,
  40. access, modify and display frames.  This section will
  41. describe each of them in turn.  As an overview, the
  42. complete list is:
  43.  
  44. (fdefine F ...) define the frame F.
  45.  
  46. (fget Fr S F D) return data facet F of slot S of frame
  47.                 Fr.
  48.  
  49. (fvalue(s) F S) return data in the :value facet of slot
  50.                 S of frame F.
  51.  
  52. (fslots F)      returns names of slots in frame F.
  53.  
  54. (ffacets F S)   returns names of facets in slot S of
  55.                 frame F.è
  56. (fput Fr S F D) adds datum D as a datum from slot S of
  57.                 frame Fr.
  58.  
  59. (fremove Fr S F D)
  60.                 removes D to facet F of slot S of frame
  61.                 Fr.
  62.  
  63. (ferase F)      removes all local information from
  64.                 frame F then deletes it.
  65.  
  66. (framep F)      true if F is the name of a frame.
  67.  
  68. (fsubsumes F1 F2)
  69.                 true if F1 subsumes F2.
  70.  
  71. (fshow F)       show definition of frame F.
  72.  
  73.  
  74. Defining Frames
  75.  
  76. (fdefine frame-name parents &rest slots)
  77.  
  78. (fdefineq frame-name parents &rest slots)
  79.  
  80. The easiest way to create a frame is just to refer to
  81. it!  For example, saying (fget 'john 'age ':value) has
  82. the side effect of establishing john as a frame if it
  83. is not one already.  Two functions are provided for
  84. explicitly creating a frame and giving it some
  85. information: fdefine and fdefineq.  The function
  86. fdefineq is just like fdefine except that it does not
  87. evaluate its arguments.  A typical call to fdefineq
  88. looks like this:
  89.  
  90.  (fdefineq cs-student student
  91.    (major (:value computer-science)))
  92.  
  93. This expression defines cs-student to be a kind of student whose 
  94. major is "computer-science". The first argument provides the 
  95. frame's name, the second its immediate subsumers in the taxonomy 
  96. and its remaining arguments (if any) its slots. The slot 
  97. specifying arguments are lists which have the structure:  
  98.  
  99.  (slot-name facet1 facet2 ... facetn)
  100.  
  101. where a facet looks like:  
  102.  
  103.  (facet-name datum1 datum2 ... datumn)
  104.  
  105. A more elaborate example of a frame definitions is:
  106.  
  107.  (fdefineq course university-thing
  108.    (name (:type string)(:min 1)(:max 1))
  109.    (number (:min 1) (:max 1))è   (department (:type dept) (:min 1))
  110.    (prerequisits (:type course))
  111.    (lecturer (:type instructor)(:min 1))
  112.    (teaching-assistant (:type ta))
  113.    (students
  114.      (:type student)
  115.      (:min 1)
  116.      (:if-added check-prerequisites)))
  117.  
  118. Note that re-defining a frame will cause the old
  119. definition to be overwritten.
  120.  
  121.  
  122. Accessing parts of Frames
  123.  
  124. Four basic functions are provided to extract
  125. information from a frame.  The functions fget and
  126. fvalues extract data stored in the facets of the slots
  127. of frames.  Fget retrieves data from arbitrary facets
  128. of a frames slot and fvalues from the :value facet.
  129. The functions fslots and ffacets operate on a more
  130. schematic level, retrieving the slots of a frame, and
  131. the facets of a slot, respectively. Whether or not
  132. inheritance is done (and the use of defaults and
  133. demons) is controlled through the use of optional
  134. keyword parameters.
  135.  
  136. (fget frame slot facet &key inherit)
  137.  
  138. The main frame accessing function is fget.  It takes
  139. three required arguments which specify a frame, slot
  140. and facet and an optional keyword parameter inherit.
  141. It returns the data in the specified frame, slot and
  142. facet.  Examples are:
  143.  
  144.  (fget 'john 'advisor :if-needed)
  145.  (fget 'john 'advisor :type
  146.      :inherit t)
  147.  (fget 'john 'advisor :type
  148.      :inherit nil)
  149.  
  150. The optional keyword parameter inherit controls whetheror not inheritance is used.  If it is not specified,
  151. then tits value defaults to that of the global variable
  152. *finherit*.
  153.  
  154. (fvalues frame slot &key inherit default demons)
  155.  
  156. The function fvalues is used to get the data in a
  157. slot's :value facet.  It is distinct from fget because
  158. the data in this facet can be represented explicitly or
  159. computed from the :default or :if-needed facets.  This
  160. function takes two required parameters which specify
  161. the frame and slot and up to three optional keyword
  162. parameters which control inheritance, the use of
  163. default values and the use of if-needed demons.èExamples are:
  164.  
  165.  (fvalues stud 'courses)
  166.  (fvalues stud 'courses :inherit nil)
  167.  (fvalues stud 'courses
  168.       :inherit t
  169.       :default nil
  170.       :if-needed nil)
  171.  
  172. The optional keyword parameters are as follows:
  173.  
  174.    - inherit - If non-nil then data can be
  175.      inherited from any of the frame's parents if
  176.      there are no local values, default values or
  177.      if-needed demons.
  178.  
  179.    - default - If non-nil then a default value
  180.      will be sought if there is no local explicit
  181.      value.
  182.  
  183.    - demons - If non-nil than if-needed demons can
  184.      be invoked to compute values there are no
  185.      local values or default values.
  186.  
  187. If any of these optional keyword variables are not
  188. specified, then their values are provided by the global
  189. variables *finherit*, *fdefault* and *fdemons*.  These
  190. are initially all set to T.
  191.  
  192. (fslots frame &key inherit)
  193.  
  194. This function returns a list of the names of the slots
  195. in the frame frame.  If the keyword parameter inherit
  196. is nil then these will include only the local slots,
  197. otherwise the list will include all local and inherited
  198. slots.
  199.  
  200. (ffacets frame slot &key inherit)
  201.  
  202. This function returns a list of the names of all of the facets in 
  203. frame frame and slot slot. As with the function fslots, the 
  204. keyword parameter inherit determines whether just the local or 
  205. the local and inherited slots are returned.
  206.  
  207. These last two functions, fslots and ffacets are useful
  208. in writing functions which operate on arbitrary frame
  209. structures.  Writing a function to display the
  210. information in a frame, for example, requires iterating
  211. over all of the slots in the frame and then iterating
  212. over all of the facets in each slot:
  213.  
  214.  (defun fshow (frame)
  215.    "displays a frame"
  216.    (format t "~%frame ~S" frame)
  217.    (foreach slot in (fslots frame)è     (format t "~%  slot ~S:" slot)
  218.      (foreach facet in (ffacets frame slot)
  219.        (format t "~%  ~S = " facet)
  220.        (foreach datum in
  221.          (fget frame slot facet)
  222.          (format t "~S "  datum))))
  223.    frame)
  224.  
  225.  
  226. Adding Information
  227.  
  228. (fput frame slot facet datum &key type demons inherit
  229. number)
  230.  
  231. This function adds a new datum to a given frame, slot
  232. and facet after checking any appropriate type and
  233. cardinality constraints.  If the datum is already a
  234. local value in the facet, then nothing is done.  If the
  235. facet is :value and if the keyword parameter :type is
  236. non-nil, then the datum is checked for proper type.
  237. The datum is then added to the facet and, if the facet
  238. is :value and the keyword parameter :demons is non-nil,
  239. any demons are run.  The :inherit keyword parameter
  240. controls whether or not inheritance is used in
  241. gathering the demons and type information.  The :number
  242. keyword parameter controls the application of any
  243. cardinality constraints (i.e. those specified by the
  244. :min and :max facets.
  245.  
  246.  
  247. Removing Information
  248.  
  249. Two primitive functions are provided for removing
  250. information from the frame system: fremove, which
  251. removes a given datum from the facet of a frames's slot
  252. and ferase which erases an entire frame.
  253.  
  254. (fremove frame slot facet datum &key demons inherit
  255. number)
  256.  
  257. This function removes the datum from the frame and slot and 
  258. facet, after checking any appropriate cardinality constraint. If 
  259. we are removing a value (e.g. the facet is :value) then any 
  260. appropriate :min constraints are checked before the value is 
  261. removed and any if-removed demons are run (provided the :demons 
  262. parameter is non-nil). The keyword parameter :inherit controls 
  263. whether or not these demons and min constraints will be 
  264. inherited.
  265.  
  266. (ferase frame &key demons inherit)
  267.  
  268. The :ferase function removes all local data in all
  269. local facets of all local slots of the frame frame via
  270. calls to fremove.  This may, of course, trigger
  271. if-removed demons.  After the data have been removed,èthe frame itself is deleted. The optional keyword
  272. parameters demons and inherit are simply passed on to
  273. fremove.
  274.  
  275.  
  276. Miscellaneous
  277.  
  278. (framep expr)
  279.  
  280. This predicate returns T if its argument is the name of
  281. a frame.
  282.  
  283. (fsubsumes expr1 expr2)
  284.  
  285. This function returns T if expr1 can be shown to
  286. subsume expr2. One of the two arguments must be a
  287. frame.  Expression E1 subsumes E2 if one of the
  288. following is true:
  289.  
  290.    - both are frames and they are equal or there
  291.      is a chain of AKO links from E2 to E1
  292.  
  293.    - E1 is a frame and there is a predicate in its
  294.      subsumes-if slot which is true of E2.
  295.  
  296.    - E2 is a frame and there is a predicate in its
  297.      subsumed-if slot which is true of E1.
  298.  
  299. The last two methods are provided in order to compare
  300. frames with other, non-frame, objects.  For example, we
  301. can define a frame number which subsumes all lisp
  302. numbers and a frame ageValue which subsumes numbers
  303. between 0 and 120 as follows:
  304.  
  305.  (fdefineq number thing
  306.    (subsumes-if (:value numberp)))
  307.  
  308.  (fdefineq ageValue number
  309.    (subsumes-if (:value validAgeP)))
  310.  
  311.  (defun validAgeP (X)
  312.    (and (numberp X)
  313.         (<= 0 X 120)))
  314.  
  315.  
  316. Displaying Frames
  317.  
  318. Two simple functions are provided for displaying the
  319. definition of a frame:  fshow displays all information
  320. in a frame and fshow-values shows just the slot values.
  321. Again, the use of inheritance, default values and
  322. demons is controlled by optional keyword parameters.
  323.  
  324. (fshow frame &key inherit)
  325. èThis function displays the specified frame, including
  326. all of its slots, facets and data.  In the keyword
  327. parameter inherit in nil, only the local information
  328. will be displayed.
  329.  
  330. (fshow-values frame &key inherit demons default)
  331.  
  332. This function displays the values for all of the slots
  333. in the specified frame.  The keyword parameters are
  334. similar to those for fvalues.
  335.  
  336.  
  337. Global Variables
  338.  
  339. PFL has a small number of global variables which
  340. control its operation.  These include:
  341.  
  342.    - *frames* - This variable is bound to a list
  343.      of the names of all of the frames in
  344.      existence.  Its initial value is NIL.
  345.  
  346.    - *finherit* - The default value for the
  347.      keyword parameter inherit.  Initially
  348.      T. Determines whether or not inheritance is
  349.      used in seeking data from facets in a slot.
  350.  
  351.    - *fdemons* - The default value for the keyword
  352.      parameter demons.  Initially T. Determines
  353.      wheter or not IF-NEEDED, IF-ADDED and
  354.      IF-REMOVED demons are invoked when seeking,
  355.      adding or removing values from a slot,
  356.      respectively.
  357.  
  358.    - *ftype* - The default value for the keyword
  359.      parameter type.  Initially T. Determines
  360.      wheter or not type checking is done when
  361.      values are added to a slot.
  362.  
  363.    - *fdefault* - The default value for the
  364.      keyword parameter default.  Initially
  365.      T. Determines whether or not the :DEFAULT
  366.      facet is used when looking for a value for a
  367.      slot and none is found.
  368.  
  369.    - *fnumber* - The default value for the keyword
  370.      parameter number.  Initially T. Determines
  371.      whether or not the :MIN and :MAX constraints
  372.      are checked when adding and removing values
  373.      from slots.
  374.  
  375.  
  376. Implementation Issues
  377.  
  378. This section describes some of the details of the
  379. Common Lisp implementation. A listing of the code canèbe found at the end of this article. We will first
  380. describe the overall organization of the program and
  381. then the representation used for frames the basic
  382. functions used to create, access and modify frames are
  383. described.
  384.  
  385. Organization of the Program
  386.  
  387. Good programming practice dictates that any large
  388. system should be broken up into smaller modules.
  389. I have followed this practice and decomposed it into the 
  390. files listed below.  (Editor's note:  the following files have 
  391. been merged into the one file PFL.LSP and can be obtained by 
  392. downloading from any AI EXPERT Bulletin Board node (see page ??) 
  393. or from AI EXPERT's account on CompuServe.)
  394.  
  395. PFL.LISP        defines the PFL system
  396.  
  397. PFLVARIABLES.LISP
  398.                 global variables
  399.  
  400. PFLMACROS.LISP  macros and small utilities
  401.  
  402. PFLBASE.LISP    basic functions
  403.  
  404. PFLDISPLAY.LISP functions to display frames
  405.  
  406. PFLTHING.LISP   standard top of all taxonomies
  407.  
  408. The file PFL.LISP defines the PFL system and can be
  409. used to load PFL.  Note the use of the "readtime
  410. conditionals" (e.g. #+ symbolics) to customize PFL to
  411. run on different systems. The file PFLVARIABLES.LISP
  412. defines and intializes all of the global variables used
  413. in PFL.  We follow the popular Lisp convention that the
  414. names of global variables begin and end with the "*"
  415. character. The file PFLMACROS.LISP contains the
  416. definitions of macros and general utilities that are
  417. used throughout the system. It is important to have these 
  418. organized into a separate file since the macro definitions are 
  419. needed whenever any other module is compiled. The main body of 
  420. the system is contained in PFLBASE.LISP. This is the largest and 
  421. most important file. Several functions for displaying frames are 
  422. found in PFLDISPLAY.LISP. Finally, some standard frames that are 
  423. to be included in every taxonomy are defined in the file 
  424. PFLTHING.LISP
  425.  
  426.  
  427. Representing a Frame
  428.  
  429. In PFL a frame is represented as a list containing the
  430. frame's name and a sublist to represent each of its
  431. local slots. Each slot list has a name and any number
  432. of facets.  Each facet has a name and any number of
  433. data.  Here is the structure schematically:è
  434.  (frame-name
  435.     (slot1-name ...)
  436.     (slot2-name ...)
  437.     (slot3-name
  438.       (facet1-name ...)
  439.       (facet2-name datum1
  440.                    datum2
  441.                    ...)
  442.         ...)
  443.      ...)
  444.  
  445. And here is an example of a list structure for a frame
  446. used to represent a person:
  447.  
  448.  (person
  449.    (ako (:value animal))
  450.    (gender (:type gender-term)
  451.            (:min 1)
  452.            (:max 1))
  453.    (spouse (:type person)
  454.            (:if-added add-inverse)))
  455.  
  456. The current implementation stores a structure which
  457. represents a frame under the frame property of the
  458. frame's name.  In addition, the global variable
  459. *frames* is bound to a list of the names of all current
  460. frames.  Thus the function which creates a frame is
  461. relatively straightforward:
  462.  
  463.  (defun fcreate (f)
  464.    "creates a frame with name F"
  465.    (setq *frames* (adjoin f *frames*))
  466.    (setf (get f 'frame) (list f)))
  467.  
  468. Indexing the frames in this way has the advantages of being very 
  469. easy to implement and allowing for extremely fact access. The 
  470. chief disadvantage is that it only allows a single, global frame 
  471. system to exist since Common Lisp's property list system is 
  472. global. This makes it impossible, for example, to maintain two 
  473. seperate knowledge bases and to quickly switch between them. A 
  474. typical alternative to this scheme is to maintain a hash-table 
  475. into which all current frames are placed, indexed by their names. 
  476. This enables one to have multiple frame systems by creating 
  477. several hash-tables.
  478.  
  479.  
  480. Accessing Data in Frames
  481.  
  482. One of the most basic operations on such a frame
  483. structure is one which gets the data associated with a
  484. particular frame, slot and facet.  This can be
  485. accomplished very easily by the internal PFL function
  486. fget-local:
  487. è (defun fget-local (frame slot facet)
  488.    ;; returns the data in a facet w/o
  489.    ;; inheritance or demons.
  490.    (cdr (assoc
  491.          facet
  492.          (cdr (assoc
  493.                slot
  494.                (cdr (frame frame)))))))
  495.  
  496. where the function frame returns the structure which
  497. represents the specified frame, creating the frame if
  498. neccessary:
  499.  
  500.  (defun frame (f)
  501.    (or (get f 'frame)
  502.        (fcreate f)))
  503.  
  504. Since the CDR of NIL is defined to be NIL in Common
  505. Lisp, this process will work even if the frame does not
  506. have the slot or facet in question.
  507.  
  508. Of course, attempting to get data may in general
  509. require that it be inherited from the frame's
  510. ancestors.  If the facet in question is the :value
  511. facet, then we may have to look for corresponding
  512. :default or :if-needed facets.  The fget function takes
  513. three required arguments specifying a frame, slot and
  514. facet and returns a list of the data found.  Whether or
  515. not inheritance is done is controlled by the optional
  516. keyword parameter :inherit.  If the facet in question
  517. is the :value facet, then we can control whether or not
  518. demons can be invoked to compute the values and whether
  519. or not default values will be accepted through the use
  520. of the optional keyword parameters :demons and default.
  521. Note that fget simply passes the job onto fget-value or
  522. fget1, depending on whether or not the facet sought is
  523. the :value facet.
  524.  
  525.  (defun fget
  526.         (frame slot facet
  527.           &key (inherit *finherit*)
  528.                (demons *fdemons*)
  529.                (default *fdefault*))
  530.    (if (equal facet :value)
  531.        (fvalues frame slot facet
  532.           :inherit inherit
  533.           :demons demons
  534.           :default default)
  535.        (fget1 frame slot facet inherit)))
  536.  
  537.  (defun fget1 (frame slot facet inherit?)
  538.     "returns data in frame, slot and facet"
  539.     (or (fget-local frame slot facet)
  540.         (if inherit?
  541.           (forsome parent in (fparents frame)è              (fget1 parent slot facet t)))))
  542.  
  543.  (defun fvalues (f s
  544.                  &key (inherit *finherit*)
  545.                       (demons *fdemons*)
  546.                       (default *fdefault*)
  547.                       (finitial f))
  548.     "returns values from frame F slot S"
  549.     (or (fget-local f s :value)
  550.         (and default
  551.              (fget-local f s :default))
  552.         (and demons
  553.              (forsome demon in
  554.                (fget-local f s :if-needed)
  555.                (listify (funcall demon finitial s))))
  556.         (and inherit
  557.              (forsome parent in (fparents f)
  558.                (fvalues parent s
  559.                   :inherit t
  560.                   :demons demons
  561.                   :default default
  562.                   :finitial finitial)))))
  563.  
  564.  
  565. Adding Data to a Slot
  566.  
  567. New data is added to a facet of a slot using rplacd to
  568. modify the list representation the facet, appending the
  569. new datum to the end of the list. The ffacet function
  570. is used to get this facet structure, creating it if
  571. neccessary.
  572.  
  573.  (defun fput-add (frame slot facet datum)
  574.     ;; adds datum to given (frame,slot,facet)
  575.     (rplacd (last (ffacet frame slot facet))
  576.             (list datum)))
  577.  
  578.  (defun ffacet (frame slot facet)
  579.     ;; returns the expression representing
  580.     ;; given (frame, slot,facet), creating
  581.     ;; it if neccessary.
  582.     (extend facet (extend slot (frame frame))))
  583.  
  584.  (defun extend (key alist)
  585.     ;; like assoc, but adds key KEY if
  586.     ;; its not in the alist AlIST.
  587.     (or (assoc key (cdr alist))
  588.         (cadr (rplacd (last alist)
  589.                       (list (list key))))))
  590.  
  591. In general, putting a value into a facet of a slot is
  592. somewhat more complex.  If the value is already
  593. present, then nothing need be done. if the facet in
  594. question is the :value facet, then we must check to see
  595. if the candidate value satisfies all of the typesèassociated with the slot (as specified in the :type
  596. facet), ensure that the slot is still open to receiving
  597. additional values (checking the :min facet), and
  598. finally, triggering any if-added demons associated with
  599. the slot. The following functions accomplishes this
  600. process:
  601.  
  602.  (defun fput (frame slot facet datum
  603.               &key (demons *fdemons*)
  604.                    (type *ftype*)
  605.                    (inherit *finherit*)
  606.                    (number *fnumber*))
  607.    ;; adds a datum to a slot.
  608.    (cond ((member datum (fget-local frame slot facet))
  609.           datum)
  610.          ((equal facet :value)
  611.           (fput-value frame slot datum
  612.              demons type inherit number))
  613.          (t
  614.           (fput-add frame slot facet datum)
  615.           datum)))
  616.  
  617.  (defun fput-value (frame slot datum demons?
  618.                     type? inherit? number?)
  619.     ;; adds value to slot if the types are ok
  620.     ;; & slot isn't full, then runs demons
  621.     (unless
  622.       (and type? (not (fcheck-types frame slot datum)))
  623.       (unless (and number?
  624.                    (not (fcheck-max frame slot)))
  625.         (fput-add frame slot :value datum)
  626.         (if demons?
  627.             (foreach demon in
  628.               (fget frame slot :if-added
  629.                     :inherit inherit?)
  630.               (funcall demon frame slot datum)))
  631.         datum)))
  632.  
  633.  
  634. Removing Values
  635.  
  636. Removing data from a facet of a frame's slot is
  637. relatively easy.  We first must ensure that the datum
  638. is indeed a locally stored one.  Then, if the facet in
  639. question is the :value facet, we must verify that the
  640. datum's removal will not leave too few data in the
  641. facet.  The actual removal can then be done with a
  642. simple call to delete.  Finally, if we are removing a
  643. value, we must run any if-removed demons associated
  644. with the slot.
  645.  
  646.  (defun fremove (frame slot facet datum
  647.                  &key (demons *fdemons*)
  648.                       (inherit *finherit*)
  649.                       (number *fnumber*))è    ;; removes datum from frame's slot's facet
  650.     (when (and (member datum
  651.                        (fget-local frame slot facet))
  652.                (or (not (eq facet :value))
  653.                    (fcheck-min frame slot)))
  654.           (delete datum (ffacet frame slot facet))
  655.           (if (and (eq facet :value) demons)
  656.               (foreach demon in
  657.                 (fget frame slot :if-removed
  658.                       :inherit inherit)
  659.                 (funcall demon frame slot datum)))))
  660.  
  661.  
  662.