Prolog-style append

This example demonstrates a Prolog-style definition of an append function using Horn implication rules. It also shows how to define and use total functions in PowerLoom®.

    Welcome to PowerLoom 3.0.1.beta

Copyright (C) USC Information Sciences Institute, 1997-2003.
PowerLoom is a registered trademark of the University of Southern California.
PowerLoom comes with ABSOLUTELY NO WARRANTY!
Type `(copyright)' for detailed copyright information.
Type `(help)' for a list of available commands.
Type `(demo)' for a list of example applications.
Type `bye', `exit', `halt', `quit', or `stop', to exit.


|= (demo 4)

Now reading from `PL:sources;logic;demos;append.ste'.
Type `?' at the pause prompt for a list of available commands.

;;; -*- Mode: Lisp; Package: STELLA; Syntax: COMMON-LISP; Base: 10 -*-

;;; Version: append.ste,v 1.14 2003/06/05 23:13:43 hans Exp

;;; Prolog-style `append' using implication rules
;;; =============================================

;;; This file demonstrates a Prolog-style definition of an `append'
;;; function using implication rules.  It also shows how to define
;;; and use total functions in PowerLoom.

;;; The best way to view this file is by calling `(demo)' and
;;; selecting it from the menu of example demos.  This demo assumes
;;; familiarity with some basic PowerLoom concepts which are described
;;; in the introductory demo (#1 on the demo menu) and other demos
;;; preceding this one.


;; Demo preamble:

|= (in-package "STELLA")
------ pause ------c


;; The module definition below is slightly different from the ones
;; seen previously, since it uses the `:shadow' keyword to shadow the
;; name `cons'.  This is necessary, since a STELLA class with the same
;; name is inherited from the STELLA module (PowerLoom's top-level
;; PL-KERNEL module currently :uses the STELLA module which causes
;; some name space pollution that will be eliminated in future
;; versions).  Without the shadowing declaration PowerLoom still would
;; have noticed the name conflict and asked the user whether to shadow
;; the name automatically.

|= (defmodule "PL-USER/PROLOG-APPEND"
  :shadow (cons))

|MDL|/PL-KERNEL-KB/PL-USER/PROLOG-APPEND

|= (in-module "PROLOG-APPEND")


|= (clear-module "PROLOG-APPEND")


|= (reset-features)

|l|(:EMIT-THINKING-DOTS :JUST-IN-TIME-INFERENCE)

|= (in-dialect KIF)

:KIF

;; We start by defining a logic concept to represent a Lisp-style cons
;; cell.  The concept is different from its Lisp analogue, since it
;; does not have any internal structure such as a `car' or `cdr' slot.
;; Instead, the semantics of constructing and appending cons-lists is
;; defined completely declaratively by the functions below and their
;; associated rules.

|= (defconcept Cons-Cell)

|c|CONS-CELL

;; Next we define a function `cons' that takes an arbitrary ?head
;; element and some pre-existing cons list ?tail and returns a new
;; cons list with ?head prepended to ?tail.

;; In a programming language such as Lisp or STELLA `cons' is a
;; constructor, i.e., for any set of legal input arguments, a new cons
;; cell gets allocated on the memory heap.  To reflect this
;; characteristic in PowerLoom, we have to define `cons' as a total
;; function.  This will allow PowerLoom to infer that for any legal
;; inputs ?h and ?t it follows that `(exists ?c (= (cons ?h ?t) ?c))'.
;; By default PowerLoom functions are not total (this is different
;; from Prolog) and the above inference is not warranted.  To specify
;; that `cons' is total we use the keyword axiom syntax `:total TRUE'
;; which simply expands to `(assert (total cons))'.  To specify a
;; keyword axiom for a unary relation such as `total' a value of TRUE
;; or FALSE must be specified.

|= (deffunction cons (?head (?tail Cons-Cell)) :-> (?cons Cons-Cell)
  :documentation "Add `?head' to the front of the cons-list `?tail'."
  :total TRUE)

|f|CONS

;; Next, we define the function `append'.  This function is not
;; specified as total, since it will be "computed" via a set of
;; implication rules:

|= (deffunction append ((?list1 Cons-Cell) (?list2 Cons-Cell)) :-> (?r Cons-Cell)
  :documentation "Append the cons-lists `?list1' and `?list2'.")

|f|APPEND

;; Let's start with creating the empty list:

|= (assert (Cons-Cell NIL))

|P|(CONS-CELL NIL)

;; Now we specify the rules that specify the semantics of `append'.
;; Each rule is a universally quantified KIF implication.  Top-level
;; free variables such as ?list1 and ?list2 are implicitly universally
;; quantified.

;; The first rule states that appending anything to the empty list NIL
;; simply returns the second list (similar to Prolog formulations, we
;; use `?result' as a kind of "output" variable):

|= (assert (=> (and (= ?list1 NIL)
                 (= ?list2 ?result))
            (= (append ?list1 ?list2) ?result)))

|P|(FORALL (?list1//NIL ?list2 ?list2)
   (<= (= (APPEND NIL ?list2) ?list2)
       TRUE))

;; The second rule handles the inductive case, where we split off a
;; head element of the first list and reduce the problem to appending
;; the shortened first list to the second:

|= (assert (=> (exists (?head ?tail ?rest)
              (and (= ?list1 (cons ?head ?tail))
                   (= ?rest (append ?tail ?list2))
                   (= ?result (cons ?head ?rest))))
            (= (append ?list1 ?list2) ?result)))

|P|(FORALL (?list1 ?list2 ?result)
   (<= (= (APPEND ?list1 ?list2) ?result)
       (EXISTS (?head ?tail ?rest)
          (AND (= (CONS ?head ?tail) ?list1)
               (= (APPEND ?tail ?list2) ?rest)
               (= (CONS ?head ?rest) ?result)))))

;; Various queries:

|= (retrieve all ?z
          (= ?z (append NIL NIL)))

There is 1 solution:
  #1: ?Z=NIL

;; The queries below generate actual cons-like structure with the help
;; of anonymous skolem individuals.  The generation of these skolems
;; is sanctioned, since `cons' was declared to be a total function:

|= (retrieve all ?z
          (= ?z (append (cons red NIL) NIL)))

There is 1 solution:
  #1: ?Z=(CONS RED NIL)

|= (retrieve all ?z
          (= ?z (append NIL (cons red NIL))))

There is 1 solution:
  #1: ?Z=(CONS RED NIL)

|= (retrieve all ?z
          (= ?z (append (cons red NIL) (cons blue NIL))))

There is 1 solution:
  #1: ?Z=(CONS RED (CONS BLUE NIL))

|= (retrieve all ?z
          (= ?z (append
                 (cons yellow (cons green NIL))
                 (append (cons red NIL) (cons blue NIL)))))

There is 1 solution:
  #1: ?Z=(CONS YELLOW (CONS GREEN (CONS RED (CONS BLUE NIL))))

;; Let's name a cons-cell (note, that our logic cons cells are different
;; from their programming languages analogues, since they are structure-
;; shared, i.e., whenever we mention `(cons green NIL)' we refer to the
;; same function term, while in the programming language there could be
;; multiple copies with identical structure):

|= (assert (= (cons green NIL) green-cons))

|P|(= (CONS GREEN NIL) GREEN-CONS)

;; Accessing the head element of green-cons:

|= (retrieve all ?m
          (exists (?t) (= (cons ?m ?t) green-cons)))

Processing check-types agenda...
There is 1 solution:
  #1: ?M=GREEN

;; Accessing both elements of green-cons: 

|= (retrieve all (?m ?t)
          (= (cons ?m ?t) green-cons))

There is 1 solution:
  #1: ?M=GREEN, ?T=NIL

|= 

Finished demo `PL:sources;logic;demos;append.ste'.

|= 

Information Sciences Institute PowerLoom Home Page
PowerLoom is a registered trademark of the University of Southern California.
Last modified: May 27, 2006