[CS logo]




CMSC 25000 - Artificial Intelligence
Winter 2004
Assignment #1  Solutions





Solution 1: [10 points]


;;;; CMSC   25000  Artificial  Intelligence  Solutions

;;; Homework 1
;;;  Problem 1
;;; count
(define (atom? x) (or (symbol? x) (number? x) (boolean? x) (null? x)))


;; contract: count: expr --> number  where  expr  is  a scheme  expression
;; purpose: to count number of atoms in the scheme expression

(define (count exp)
  (cond
    ((atom? exp) 1)
    ((empty? exp) 0)
    (else (+ (count (first exp)) (count (rest exp))))))



;;; tests
(display  "testing count")
(= (count 'a)  1)
(= (count '())  1)
(= (count '(a b))  3)
(= (count '((the sun) (rose (over (the clouds)))))  11)
(= (count '(a (b . c)))  4)



Solution  2: [20 points]

;;;; -*- mode:Scheme -*- ;;;;

;; Part of BINDINGS abstraction
(define *null-bindings* '(bindings)) ;; initial value of bindings

;;; UTILITIES
(define first car)
(define rest cdr)
(define second cadr)

;;;; MATCHER

(define (match p d) (do-match p d *null-bindings*))

(define (do-match p d bindings)
  ;;Arguments:    Pattern, datum, optional bindings.
  ;;Returns:    A list of bindings or #f
  ;;Remarks:    Pattern variables are indicated by (? <variable name>)
  ;;        Prolog's nameless variable is indicated by (? _)
  (cond ((and (null? p) (null? d))
     bindings)
    ((and (atom? p) (atom? d))
         (match-atoms p d bindings))
        ((simple-variable? p)
         (match-simple-variable p d bindings))
    ((segment-variable? p)       
     ;; rule out standalone segment var - it's not clear what that means.
     ;; all other segment variables will be handled by match-pieces.
         #f)
        ((pair? p)
     ;; We don't check d here because ((* x)) matches ()
         (match-pieces p d bindings))
    (else #f)))

(define (match-atoms p d bindings)
  ;;Are the pattern and datum the same:
  (if (eqv? p d)            ; eqv? not eq? because of numbers.
      ;;If so, return the value of BINDINGS:
      bindings
      ;;Otherwise, return #f
      #f))

(define (match-simple-variable variable-expression d bindings)
  (let ((binding (find-binding variable-expression bindings)))
    ;;Is the pattern variable on the list of bindings:
    (if binding
        ;;If it is, substitute its value and try again:
        (do-match (extract-value binding) d bindings)     
        ;;Otherwise, add new binding:
        (add-binding variable-expression d bindings))))

(define (match-pieces p d bindings)
  (if (segment-variable? (first p))
      (match-segment-variable (first p) (rest p) d bindings)
      (if (pair? d)
      (let ((result (do-match (first p) (first d) bindings)))
        ;;See if the FIRST parts match producing new bindings:
        (if result
        ;;If they do match, try the REST parts using the resulting bindings:
        (do-match (rest p) (rest d) result)
        ;;If they do not match, fail.
        #f))
      #f)))

(define (match-segment-variable
     variable-expression rest-p d bindings)
  ;; THIS IS THE CODE YOU HAVE TO PROVIDE!
(let  ((result  (matcher  rest-p d bindings empty d)))
  (if (first result)
       (let ((binding (find-binding variable-expression bindings)))
    ;;Is the pattern variable on the list of bindings:
    (if binding
        ;;If it is, substitute its value and try again:
        (do-match (cons (extract-value binding) rest-p) d bindings)     
        ;;Otherwise, add new binding and recurse:
        (do-match  rest-p  (rest result)  (add-binding variable-expression (first result) bindings))))
  #f)))         
           
     
 
 
 

(define (matcher rest-p d  bindings matched-d rest-d)
  (let ((result (do-match rest-p d bindings)))
    (if  (or result (empty? d))
        (cons matched-d  rest-d)
        (matcher rest-p (rest d)  bindings (append matched-d (cons (first d) empty)) (rest rest-d)))))
   
;;;; BINDINGS ABSTRACTION

;;; adds a new binding for a variable to a bindings list.
;;; a variable expression is of the form (? x) or (* x)
(define (add-binding variable-expression datum bindings)
 (if (nameless-variable? variable-expression)
     ;; If it is a nameless variable, it matches anything but does not add bindings
     bindings
     ;; add a new binding, remembering that the car of the list is the symbol 'bindings
     (cons (first bindings)
       (cons (list (variable-name variable-expression) datum)
         (rest bindings)))))

;;; returns the binding for a variable (or #f if none)
;;; a variable expression is of the form (? x) or (* x)
(define (find-binding variable-expression bindings)
  (if (and bindings
       (not (nameless-variable? variable-expression)))
    ;; If it's a nameless variable, don't look for binding.  Otherwise, use
    ;; assoc to find the binding.  (assoc x y) looks for a list in y whose car
    ;; is x and returns that, which is just what we need.
    (assoc (variable-name variable-expression)
       ;; Skip the symbol at the beggining of bindings list.
       (rest bindings))
    #f))

(define (extract-key binding) (first binding))
(define (extract-value binding) (second binding))

;;; VARIABLES

;;; A test for a (? x) type of variable.
(define (simple-variable? x)
  (and (pair? x) (eq? '? (first x))))

;;; A test for a (* x) type of variable.
(define (segment-variable? x)
  (and (pair? x) (eq? '* (first x))))

;;; A test for a (? _) or (* _) type of variable.
(define (nameless-variable? x)
  (and (pair? x) (memq (first x) '(? *)) (eq? '_ (second x))))

;;; Get the name for a variable, given (? var)
(define (variable-name x) (second x))

;;; UTILITIES

;;; Something that has no further structure to match and can be compared
;;; directly (using eqv?).
(define (atom? x) (or (symbol? x) (number? x) (boolean? x) (null? x)))

;;; Add elt to the end of lst.
(define (add-to-end elt lst)
  (append lst (list elt)))


;;; TESTS
(match '(a (? x) b c) '(a d b c)) ;;; ==>  (bindings (x d))
(match '(a (? x) b (? x)) '(a c b c)) ;;; == >  (bindings (x c))
(match '(a c b d) '(a c b d))  ;;;;==>  (bindings)
(match '(a (?x) b (? x)) '(a c b d)) ;;;;==> #f 
(match '((* x) c) '(a b c))  ;;;==> (bindings (x (a b)))
(match '(a (* x) c) '(a b c)) ;;;==> (bindings (x (b)))
(match '(a (* x) c (* y) e) '(a b b b c d d d e)) ;;; ==> (bindings (y (d d d)) (x (b b b)))
(match '(a (* x) c) '(a c)) ;;;==> (bindings (x ()))
(match '(a (* x) c (* x)) '(a b c d)) ;;;==> #f


Questions?  Email:  vikass@cs.uchicago.edu