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