ShaughanLavine - 09 Mar 2010 - 19:26 - 1.26 " class="twikiLink">TWiki> Courses Web>ShaughanLavine - 11 Dec 2009 - 21:06 - 1.16 " class="twikiLink">SymbolicLogicA>PropositionalCalculusEasy (08 Oct 2009, TWikiAdminGroup)EditAttach
;;
;;; File: "mendelsonpropositionaleasy.scm"
;;; Copyright (c) 2009 by Shaughan Lavine. All Rights Reserved.

;;; Called "easy" because this is just a naive implementation of Mendelson's
;;; definitions for teaching purposes, rather than an efficient logical system.
;;; For example, everything is a string. In Scheme, it would make much more sense
;;; to use lists, but that is not Mendelson's presentation, and for good reason:
;;; He isn't using Scheme or any other programming language.

;;;------------------------------------------------------------------------
;;;| This file, as supplied, WILL NOT WORK: the libraries are not provided.|
;;;| I'll supply a zipped version soon that has everything.                |
;;;------------------------------------------------------------------------

(include "include-gam.scm") ; Includes srfi1, srfi2, srfi13, srfi14
(namespace ("mendelson#"))
(##include "~~/lib/gambit#.scm") ; Gambit primitives added in their namespace
(include "include-gam#.scm") ; srfi1, srfi2, srfi13, srfi14 in their namespaces

;;;==========================================================================

;;; Constructors for propositional calculus

;; The obvious and natural constructors for propositional calulus
;; appear commented out immediately below. The slightly more
;; complicated ones actually used permit dropping parentheses,
;; which is useful for displaying formulas with parentheses
;; hidden according to Mendelson's conventions. They get used in
;; the Printing and Displaying section below.

;; (define (make-statement-letter let #!optional (num #f))
;;   (if (char-set-contains? char-set:upper-case char) ; test from srfi14
;;                                         ; used instead of
;;                                         ; char-upper-case?
;;                                         ; for non-ASCII
;;                                         ; character sets
;;       (cond ((not num)(string char))
;;             ((and (integer? num)
;;                   (exact? num)
;;                   (positive? num))
;;              (string-append (string char)
;;                             (number->string num)))
;;             (else #f))
;;       #f))

;; ;; '(string-join list delimiter 'suffix) makes a string out of a list of
;; ;; strings, putting delimiter after each.
;; (define (space-string-join lis) (string-join (map string-trim-both lis) " " 'suffix))

;; (define (make-negation statement-frm)
;;   (space-string-join (list "(" "-|" statement-frm ")")))

;; (define (make-binary-connective connective left-statement-frm right-statement-frm)
;;   (space-string-join (list "(" left-statement-frm connective right-statement-frm ")")))

;; (define (make-conjunction left-statement-frm right-statement-frm)
;;   (make-binary-connective "^" left-statement-frm right-statement-frm))

;; (define (make-disjunction left-statement-frm right-statement-frm)
;;   (make-binary-connective "v" left-statement-frm right-statement-frm))

;; (define (make-conditional left-statement-frm right-statement-frm)
;;   (make-binary-connective "=>" left-statement-frm right-statement-frm))

;; (define (make-biconditional left-statement-frm right-statement-frm)
;;   (make-binary-connective "<=>" left-statement-frm right-statement-frm))

(define (make-statement-letter let #!optional (num #f) (parens #t))
                                        ; parens is optional, defaults to #t.
                                        ; #t if parentheses are supplied normally
  (if (char-set-contains? char-set:upper-case char) ; test from srfi14
                                        ; used instead of
                                        ; char-upper-case?
                                        ; for non-ASCII
                                        ; character sets
      (cond ((not num)(string char))
            ((and (integer? num)
                  (exact? num)
                  (positive? num))
             (string-append (string char)
                            (number->string num)))
            (else #f))
      #f))

(define (maybe-parenthesize strin tst)
  (if tst
      (string-append "( " strin ") ")
      strin))

;; '(string-join list delimiter 'suffix) makes a string out of a list of
;; strings, putting delimiter after each.
(define (space-string-join lis) (string-join (map string-trim-both lis) " " 'suffix))

(define (make-negation statement-frm #!optional (parens #t))
  (maybe-parenthesize
   (space-string-join (list "-|" statement-frm))
   parens))

(define (make-binary-connective
         connective left-statement-frm right-statement-frm #!optional (parens #t))
  (maybe-parenthesize
   (space-string-join (list left-statement-frm connective right-statement-frm))
   parens))

(define (make-conjunction left-statement-frm right-statement-frm)
  (make-binary-connective "^" left-statement-frm right-statement-frm))

(define (make-disjunction left-statement-frm right-statement-frm)
  (make-binary-connective "v" left-statement-frm right-statement-frm))

(define (make-conditional left-statement-frm right-statement-frm)
  (make-binary-connective "=>" left-statement-frm right-statement-frm))

(define (make-biconditional left-statement-frm right-statement-frm)
  (make-binary-connective "<=>" left-statement-frm right-statement-frm))

;;; Parsers

(define (statement-letter strin)
  (and-let* ; srfi2 Like let*, but returns '#f if any of the values is '#f
   (((string? strin))(stri (string-trim-right strin))) ; Final space is optional
   (cond ((eqv? (string-length stri) 1)
          (let ((char (string-ref stri 0)))
            (if (char-set-contains? char-set:upper-case char) (list "statement letter" stri)  #f)))
         ((> (string-length stri) 1)
          (let ((char (string-ref stri 0))
                (num (string->number (substring/shared stri 1))))
            (if (and (char-set-contains? char-set:upper-case char)
                     (number? num)(positive? num) (exact? num))
                (list "statement letter" strin)
                #f)))
         (else #f))))

(define (statement-letter-letter strin)
  (string-ref strin 0))

(define (statement-letter-subscript strin)
  (if (> (string-length strin) 1)
      (string->number (substring/shared strin 1))
      #f))

(define (statement-letter-list-statement-letter lis)
  (second lis))

(define (negation strin)
  (if (and
       (string? strin)
       (>= (string-length strin) 8)
       (string-prefix? "( -| " strin)
       (string-suffix? ") " strin))
      (list "-|" (string-drop-right (string-drop strin 5) 2)) ; drop "( -| " on the left
                                        ; then ") " on the right.
      #f))

(define (mangle alist anindex afunc) ; 'receive is the macro of srfi8, though it is used in, e.g., srfi1,
                                        ; and so it is taken from there.
                                        ; 'mangle takes a list and an index and returns a length three list of
                                        ; the item at the index, afunc applied to the list of items before the index,
                                        ; and afunc applied to the list of items after the index.
  (receive (left-sentential-form-list rest) (split-at alist anindex)
    (receive (op right-sentential-form-list) (car+cdr rest)
      (list op (afunc left-sentential-form-list) (afunc right-sentential-form-list)))))

(define (match lis) ; If lis begins with "(", returns the index of the matching ")".
                                        ; Otherwise, returns 0.
  (let depth-indx ((dpth 0) (indx 0) (lis lis))
    (cond
     ((null? lis) #f)
     ((equal? "(" (first lis)) (depth-indx (+ dpth 1) (+ indx 1) (cdr lis)))
     ((equal? ")" (first lis)) (if (equal? dpth 1) indx
                                   (depth-indx (- dpth 1) (+ indx 1) (cdr lis))))
     (else (if (equal? dpth 0)
               0
               (depth-indx dpth (+ indx 1) (cdr lis)))))))

(define (binary-connective strin)
  (if (and
       (string? strin)
       (string-prefix? "( " strin)
       (not (string-prefix? "( -| " strin))
       (string-suffix? ") " strin))
                                        ; 'string-tokenize converts a string into the list of its
                                        ;  maximal substrings of nonwhitespace printing characters
      (let* ((lis (string-tokenize (string-drop-right (string-drop strin 2) 2))))
             (mangle lis (+ (match lis) 1) space-string-join))
      #f))

(define (binary-connective-is statement-form-strin connective-strin)
  (let ((reslt (binary-connective statement-form-strin)))
    (if (and reslt
             (equal? connective-strin (first reslt))) reslt
             #f)))

(define (conjunction strin) (binary-connective-is strin "^"))
(define (disjunction strin) (binary-connective-is strin "v"))
(define (conditional strin) (binary-connective-is strin "=>"))
(define (biconditional strin) (binary-connective-is strin "<=>"))

;;; Tests
;;; Only one is really needed: Given (statement-form strin),
;;; one can test for a conjunction, for example, with
;;; (and (conjunction strin) (statement-form strin)).
;;; More efficient tests are, in fact, provided below.

(define (nullary-operator strin) (cond ((member strin  '("statement letter")) => first)
                                       (else #f)))

(define (unary-operator strin) (cond ((member strin '("-|")) => first)
                                     (else #f)))

(define (binary-operator strin) (cond ((member strin '("^" "v" "=>" "<=>")) => first)
                                      (else #f)))

;; '(statement-letter strin) and '(negation strin) should be '(nullary-connective strin) and
;; '(unary-connective strin) but that isn't worth implementing while there is only one
;; connective of each kind.
(define (statement-form strin)
  (cond
   ((statement-letter strin) => (lambda (res) res))
   ((negation strin) =>
    (lambda (res)
      (and-let*
       ((negatd (statement-form (second res))))
       (list (first res) negatd))))
   ((binary-connective strin) =>
    (lambda (res)
      (and-let* ((op (binary-operator (first res)))
                 op ; Tests that op-rest isn't #f
                 (parsed-left-statement-frm (statement-form (second res)))
                 (parsed-right-statement-frm (statement-form (third res))))
                (list op parsed-left-statement-frm parsed-right-statement-frm))))
   (else #f)))

(define (statement-form-kind-list lis) (first lis))

(define (statement-form-kind strin) (and-let* ((parsd (statement-form strin))) (first parsd)))

(define (statement-letter-list lis) (equal? "statement letter"  (first lis)))

(define (nullary-statement-form-list lis) (nullary-operator (first lis)))

(define (negation-statement-form-list lis) (equal? "-|" (first lis)))

(define (unary-statement-form-list lis) (unary-operator (first lis)))

(define (conjunction-statement-form-list lis) (equal? "^" (first lis)))

(define (disjunction-statement-form-list lis) (equal? "v" (first lis)))

(define (conditional-statement-form-list lis) (equal? "=>" (first lis)))

(define (biconditional-statement-form-list lis) (equal? "<=>" (first lis)))

(define (binary-statement-form-list lis) (binary-operator (first lis)))

(define (statement-letter-list-statement-letter lis) (string-trim-right (second lis)))

(define (left-statement-form-list lis)
  (and (or
        (unary-statement-form-list lis)
        (binary-statement-form-list lis))
       (second lis)))

(define (right-statement-form-list lis)
  (and (binary-statement-form-list lis)
       (third lis)))

(define (statement-form-kind-is? strin kind) (equal? (statement-form-kind strin) kind))

;; The obvious definition for 'statement-letter? is what follows commented out,
;; but what follows that is more efficient.
;; (define (statement-letter? strin) (statement-form-kind-is? strin "statement letter"))
(define (statement-letter? strin) (statement-letter strin))

(define (negation? strin) (statement-form-kind-is? strin "-|"))

(define (conjunction? strin) (statement-form-kind-is? strin "^"))

(define (disjunction? strin) (statement-form-kind-is? strin "v"))

(define (conditional? strin) (statement-form-kind-is? strin "=>"))

(define (biconditional? strin) (statement-form-kind-is? strin "<=>"))

;;; Truth-functional semantics
;;; What we're doing here is weird from the point of view of programming:
;;; it would be much simpler and more efficient to use Schemes built-in
;;; logical operators. But Mendelson is doing everything from scratch, as
;;; did those who wrote Scheme, and so are we.

;; A few auxiliary functions:

(define (pair-statement-letter<? l1 l2)
  (if
   (and
    (statement-letter l1)
    (statement-letter l2))
   (let ((l1l (statement-letter-letter l1))
         (l2l (statement-letter-letter l2))
         (l1s (statement-letter-subscript l1))
         (l2s (statement-letter-subscript l2)))
     (or
      (char<? l1l l2l)
      (and
       (char=? l1l l2l)
       (or
        (and (not l1s) l2s)
        (and l2s (< l1s l2s))))))
   #f))

(define (statement-letter<? . strings)
  (cond
   ((null-list? strings) #t)
   ((and (statement-letter? (first strings))
         (null-list? (cdr strings))) #t)
   ((receive (firs rest)(car+cdr strings) ; A more efficient version of
                                        ; (let ((firs (first strings))(rest (cdr strings)))
      (and
       (pair-statement-letter<? firs (first rest))
       (apply statement-letter<? rest)))
    #t)
   (else #f)))

(define (uniq-sorted lis elt< #!optional (= equal?))
  (list-delete-neighbor-dups
   (list-merge-sort lis elt<) =))

;; It is assumed that lis is of the form (statement-form strin) and that lis
;; is not #f
(define (unsorted-statement-letters-of-list lis)
  (cond
   ((nullary-statement-form-list lis)
    (list (statement-letter-list-statement-letter lis)))
   ((unary-statement-form-list lis)
    (unsorted-statement-letters-of-list (left-statement-form-list lis)))
   ((binary-statement-form-list lis)
    (append (unsorted-statement-letters-of-list (left-statement-form-list lis))
            (unsorted-statement-letters-of-list (right-statement-form-list lis))))
   (else #f)))

(define (statement-letters-of-list lis)
  (uniq-sorted (unsorted-statement-letters-of-list lis) pair-statement-letter<?))

(define (statement-letters-of strin)
  (and-let* ((lis (statement-form strin)))
            (statement-letters-of-list lis)))

(define (apply-and lis) ; Needed because 'and is a macro
  (if (null-list? lis) #t
      (and (first lis) (apply-and (cdr lis)))))

(define (statement-letters-of-list-of-strings lis)
  (and-let* ((lis (map statement-form lis))((apply-and lis)))
            (uniq-sorted
             (append-map unsorted-statement-letters-of-list lis)
             pair-statement-letter<?)))

;; Our truth values will be 'T and 'F, not the built-in booleans #t and #f of scheme
;; Thus, "T" is a statement letter, but 'T is a truth value, eliminating Mendelson's ambiguity
(define (is-a-truth-value obj) (memq obj '(T F)))

(define (is-true? obj)(equal? obj 'T))

(define (lookup obj tabl)
  (cond ((assoc obj tabl) => second)
        (else #f)))

(define not-tt '((T F)
                 (F T)))

(define and-tt '(((T T) T)
                 ((F T) F)
                 ((T F) F)
                 ((F F) F)))

(define or-tt '(((T T) T)
                ((F T) T)
                ((T F) T)
                ((F F) F)))

(define if-tt '(((T T) T)
                ((F T) T)
                ((T F) F)
                ((F F) T)))

(define iff-tt '(((T T) T)
                 ((F T) F)
                 ((T F) F)
                 ((F F) T)))

;; A truth-list is a list of 'Ts and 'Fs

(define (truth-assign statement-letter-lis truth-value-lis)
  (zip  statement-letter-lis truth-value-lis))

(define (number->truth-value-list num lgth)
  (case lgth ((0) '())
        (else (cons (if (even? num) 'T 'F)
                    (number->truth-value-list (quotient num 2)(- lgth 1))))))

(define (list-all-truth-value-lists n)
  (map (lambda (num)(number->truth-value-list num n))(list-tabulate (expt 2 n) values)))

(define (compute-truth-value-list statement-form-lis truth-assig)
  (let
      ((ctvl (lambda (sfl) (compute-truth-value-list sfl truth-assig))))
                                        ; ctvl is merely to avoid repeating 'truth-assig over and over
    (cond
     ((statement-letter-list statement-form-lis)
      (lookup (statement-letter-list-statement-letter statement-form-lis) truth-assig))
     ((negation-statement-form-list statement-form-lis)
      (lookup
       (ctvl (left-statement-form-list statement-form-lis))
       not-tt))
     ((conjunction-statement-form-list statement-form-lis)
      (lookup
       (list
        (ctvl (left-statement-form-list statement-form-lis))
        (ctvl (right-statement-form-list statement-form-lis)))
       and-tt))
     ((disjunction-statement-form-list statement-form-lis)
      (lookup
       (list
        (ctvl (left-statement-form-list statement-form-lis))
        (ctvl (right-statement-form-list statement-form-lis)))
       or-tt))
     ((conditional-statement-form-list statement-form-lis)
      (lookup
       (list
        (ctvl (left-statement-form-list statement-form-lis))
        (ctvl (right-statement-form-list statement-form-lis)))
       if-tt))
     ((biconditional-statement-form-list statement-form-lis)
      (lookup
       (list
        (ctvl (left-statement-form-list statement-form-lis))
        (ctvl (right-statement-form-list statement-form-lis)))
       iff-tt)))))

(define (compute-truth-value statement-frm truth-assig)
  (and-let* ((sfl (statement-form statement-frm)))
            (compute-truth-value-list sfl truth-assig)))

(define (truth-assignments-for-statement-letter-list-map mapped-func statement-letter-lis)
  (let ((lengt (length statement-letter-lis)))
    (map mapped-func
         (list-tabulate (expt 2 lengt)
                        (lambda (num)
                          (truth-assign statement-letter-lis
                                        (number->truth-value-list num lengt)))))))

(define (truth-assignments-for-statement-form-list-map mapped-func statement-form-lis)
  (let* ((statement-letter-lis (statement-letters-of-list statement-form-lis)))
    (truth-assignments-for-statement-letter-list-map mapped-func statement-letter-lis)))

(define (truth-value-list-of-statement-form-list statement-form-lis)
  (truth-assignments-for-statement-form-list-map
   (lambda (truth-assig)
     (compute-truth-value-list statement-form-lis truth-assig))
   statement-form-lis))

(define (truth-value-list-of-statement-form statement-frm)
  (and-let* ((sfl (statement-form statement-frm)))
            (truth-value-list-of-statement-form-list sfl)))

(define (all-T? truth-value-lis)
  (null? (remove is-true? truth-value-lis)))

(define (tautology? statement-frm)
  (and-let* ((tt  (truth-value-list-of-statement-form statement-frm)))
            (all-T? tt)))

(define (tautological-consequence? statement-form-lis statement-frm)
  (and-let* ((statement-lets
              (statement-letters-of-list-of-strings
               (cons statement-frm statement-form-lis)))
             (lengt (length statement-lets)))
            (all-T?
             (map (lambda (truth-assig)
                    (compute-truth-value statement-frm truth-assig))
                  (filter
                   (lambda (truth-assig)
                     (all-T?
                      (map (lambda (sen-fun)
                             (compute-truth-value sen-fun truth-assig))
                           statement-form-lis)))
                   (list-tabulate (expt 2 lengt)
                                  (lambda (num)
                                    (truth-assign statement-lets
                                                  (number->truth-value-list num lengt)))))))))

(define (truth-table-of-statement-form statement-frm)
  (and-let* ((sfl (statement-form statement-frm)))
            (truth-assignments-for-statement-form-list-map
             (lambda (truth-assig)
               (list (map second truth-assig)
                     (compute-truth-value-list sfl truth-assig)))
             sfl)))

;;; Disjunctive normal form

(define (make-false-statement-form statement-let)
  (make-conjunction statement-let (make-negation statement-let)))

(define (binary-join statement-form-lis make-binary-connectiv)
  (if (null? (cdr statement-form-lis))
      (first statement-form-lis)
      (make-binary-connectiv
       (conjoin (drop-right statement-form-lis 1))
       (last statement-form-lis))))

(define (conjoin statement-form-lis)
  (binary-join statement-form-lis make-conjunction))

(define (disjoin statement-form-lis)
  (binary-join statement-form-lis make-disjunction))

(define (disjunctive-normal-form truth-tabl statement-letter-lis)
  (and-let* (((apply = (map length
                            (cons statement-letter-lis
                                  (map first truth-tabl)))))
             (filtered-truth-table-lins
              (filter-map (lambda (truth-table-lin)
                            (if (equal? 'T (second truth-table-lin))
                                (first truth-table-lin)
                                #f))
                          truth-tabl)))
            (if (null? filtered-truth-table-lins)
                (disjoin (map make-false-statement-form statement-letter-lis))
                (disjoin (map
                          (lambda (filtered-truth-table-lin)
                            (let ((truth-assig (truth-assign statement-letter-lis filtered-truth-table-lin)))
                              (conjoin
                               (map (lambda (statement-let)
                                      (cond ((equal? 'T (lookup statement-let truth-assig)) statement-let)
                                            ((equal? 'F (lookup statement-let truth-assig)) (make-negation statement-let))))
                                    statement-letter-lis))))
                          filtered-truth-table-lins)))))

(define (disjunctive-normal-form-of-statement-form statement-frm)
  (disjunctive-normal-form (truth-table-of-statement-form statement-frm)
                           (statement-letters-of statement-frm)))

(define (list-of-statement-letters int)
  (list-tabulate int
                 (lambda (n)
                   (make-statement-letter
                    (integer->char (+ 65 (remainder n 26)))
                                        ; The ASCII codes for A... are 65...
                    (let ((q (quotient n 26)))
                      (if (zero? q) #f q))))))

(define (disjunctive-normal-form-of-truth-table truth-tabl)
  (disjunctive-normal-form truth-tabl
                           (list-of-statement-letters (length (first (first truth-tabl))))))

;;; Printing and displaying

;;; Basic statement-form display

(define (process-strin strin beginnin endin mappin)
  (string-append
   beginnin
   (apply string-append (map mappin (string-tokenize strin)))
   endin))

(define tex-beginning "\\[")

(define tex-ending "\\]")

(define (tex-mapping obj)
  (cond
   ((integer? obj) (string-append "_{" (number->string obj) "}"))
   ((equal? "-|" obj) "\\lnot ")
   ((equal? "^" obj) "\\land ")
   ((equal? "v" obj) "\\lor ")
   ((equal? "=>" obj) "\\Rightarrow ")
   ((equal? "<=>" obj) "\\Leftrightarrow ")
   ((equal? 'T obj) "\\mathsf{T}")
   ((equal? 'F obj) "\\mathsf{F}")
   (else obj)))

(define (tex-display statement-frm)
  (begin
    (display (process-strin statement-frm tex-beginning tex-ending tex-mapping))
    (newline)))

(define twiki-beginning "%\\[")

(define twiki-ending "\\]%")

(define (twiki-mapping obj)
  (cond
   ((integer? obj) (string-append "_{" (number->string obj) "}"))
   ((equal? "-|" obj) "\\lnot ")
   ((equal? "^" obj) "\\land ")
   ((equal? "v" obj) "\\lor ")
   ((equal? "=>" obj) "\\Rightarrow ")
   ((equal? "<=>" obj) "\\Leftrightarrow ")
   ((equal? 'T obj) "\\mathsf{T}")
   ((equal? 'F obj) "\\mathsf{F}")
   (else obj)))

(define (twiki-display statement-frm)
  (begin
    (display (process-strin statement-frm twiki-beginning twiki-ending twiki-mapping))
    (newline)))

;; The utf8 display functions will only work properly if you have an appropriate font---one
;; that has the symbols---installed, and if your encoding is set to utf8. The font I use is
;; DejaVu Sans Mono.

(define utf-beginning "")

(define utf-ending "")

(define (utf-mapping obj)
  (cond
   ((integer? obj) (number->string obj))
   ((equal? "-|" obj) "¬")
   ((equal? "^" obj) "&#8743;")
   ((equal? "v" obj) "&#8744;")
   ((equal? "=>" obj) "&#8658;")
   ((equal? "<=>" obj) "&#8660;")
   ((equal? 'T obj) "T")
   ((equal? 'F obj) "F")
   (else obj)))

(define (utf-display statement-frm)
  (begin
    (display (process-strin statement-frm utf-beginning utf-ending utf-mapping))
    (newline)))

;;; Dropping parentheses according to precedence
;;; and associated display

(define (list<= lis . res)
  (if
   (or (null? res)
       (null? (cdr res)))
   #t
   (and (member (second res) (member (first res) lis))
        (list< lis (drop res 2)))))

(define (list< lis . res)
  (if
   (or (null? res)
       (null? (cdr res)))
   #t
   (and  (member (second res) (member (first res) lis))
         (not (equal? (second res) (first res)))
         (list<= lis (drop res 2)))))

(define statement-form-kind-order
  '("statement letter" "-|" "^" "v" "=>" "<=>"))

(define (statement-form-kind< . res)
  (apply list< statement-form-kind-order res))

(define (statement-form-kind<= . res)
  (apply list<= statement-form-kind-order  res))

(define (statement-form-list->statement-form statement-form-lis)
                                        ; This could have come much earlier, but it wasn't needed.
                                        ; The version here includes optional parentheses.
  (cond
   ((statement-letter-list statement-form-lis)
    (statement-letter-list-statement-letter statement-form-lis))
   ((negation-statement-form-list statement-form-lis)
    (make-negation
     (statement-form-list->statement-form
      (left-statement-form-list statement-form-lis))
     (last statement-form-lis))) ; parens
   ((binary-statement-form-list statement-form-lis)
    (make-binary-connective
     (statement-form-kind-list statement-form-lis)
     (statement-form-list->statement-form
      (left-statement-form-list statement-form-lis))
     (statement-form-list->statement-form
      (right-statement-form-list statement-form-lis))
     (last statement-form-lis))))) ; parens

(define (deparenthesize-list statement-form-lis)
  (let ((parens #f)) ; The outermost parentheses are dropped by setting parens to #f here.
                                        ; Value can't be #f in and-let*: that makes the and-let* take value #f.
    (let deparen ((statement-form-lis statement-form-lis)
                  (parens parens))
      (let ((main-connectiv (statement-form-kind-list statement-form-lis)))
        (cond
         ((statement-letter-list statement-form-lis)
          (append statement-form-lis (list parens)))
         ((negation-statement-form-list statement-form-lis)
          (list "-|"
                (deparen
                 (left-statement-form-list statement-form-lis)
                 (statement-form-kind<
                  main-connectiv
                  (statement-form-kind-list
                   (left-statement-form-list statement-form-lis))))
                                        ; If '(statement-form-kind< ... is #f,
                                        ; that turns off the parentheses in the make-* functions.
                parens))
         ((binary-statement-form-list statement-form-lis)
          (list main-connectiv
                (deparen
                 (left-statement-form-list statement-form-lis)
                 (statement-form-kind<
                  main-connectiv
                  (statement-form-kind-list
                   (left-statement-form-list statement-form-lis))))
                (deparen
                 (right-statement-form-list statement-form-lis)
                 (statement-form-kind<= ; <= on the right because we associate to the left
                  main-connectiv
                  (statement-form-kind-list
                   (right-statement-form-list statement-form-lis))))
                parens)))))))

(define (deparenthesize statement-frm)
  (statement-form-list->statement-form
   (deparenthesize-list (statement-form statement-frm))))

(define (tex-pretty-display statement-frm)
  (tex-display (deparenthesize statement-frm)))

(define (twiki-pretty-display statement-frm)
  (twiki-display (deparenthesize statement-frm)))

(define (utf-pretty-display statement-frm)
  (utf-display (deparenthesize statement-frm)))

;;; Display truth tables
;;; This is a pain because they are abbreviated truth tables

(define (tokenized-deparenthesized-statement-form->sub-statement-form-list-list statement-form-lis)
                                        ; Takes a statement form list and returns a
                                        ; list of statement form lists that maps
                                        ; each token of the tokenized list of the
                                        ; deparenthesized statement form to the
                                        ; statement form list with main connective
                                        ; at that position or #f
  (let ((paren-tkn (lambda (sfl) (if (last sfl) '(#f) '())))) ; #f if there are parens, nothing otherwise
    (let tdsf->ssfll ((lis (deparenthesize-list statement-form-lis)))
      (cond ; based on statement-form-list->statement-form statement-form-lis
       ((statement-letter-list lis) (list lis))
       ((negation-statement-form-list lis)
        (append
         (paren-tkn lis)
         (list lis)
         (tdsf->ssfll
          (left-statement-form-list lis))
         (paren-tkn lis)
         ))
       ((binary-statement-form-list lis)
        (append
         (paren-tkn lis)
         (tdsf->ssfll
          (left-statement-form-list lis))
         (list lis)
         (tdsf->ssfll
          (right-statement-form-list lis))
         (paren-tkn lis)
         ))))))

(define (abbreviated-truth-table-layout statement-frm)
  (let* ((sfl (statement-form statement-frm))
         (sfll
          (tokenized-deparenthesized-statement-form->sub-statement-form-list-list
           sfl)))
    (append
     (list (string-tokenize (deparenthesize statement-frm)))
     (truth-assignments-for-statement-form-list-map
      (lambda (truth-assig)
        (map (lambda (sfl)
               (if sfl
                   (compute-truth-value-list sfl truth-assig)
                   " ")) sfll))
      sfl))))

(define (truth-value-mapping obj)
  (cond
   ((eq? obj 'T) "T")
   ((eq? obj 'F) "F")
   (else " ")))

(define (display-abbreviated-truth-table statement-frm)
  (let* ((ttl (abbreviated-truth-table-layout statement-frm))
         (sft (first ttl))
         (space-lis
          (map
           (lambda (strin)
             (make-string ; string of spaces to fill in Ts and Fs
              (- (string-length strin) 1)
              #\space))
           sft)))
    (begin
      (display (string-append (string-concatenate sft) "\n"))
      (map
       (lambda (lin)
         (display
          (string-concatenate
           (append
            (map string-append space-lis
                 (map truth-value-mapping lin))
            '("\n")))))
       (cdr ttl)))) #!void)

(define (process-abbreviated-truth-table-list
         lis beginnin endin mappin col-sep start-form end-form
         #!optional (args #f) (first-col-sep col-sep) (last-col-sep col-sep))
  (string-append
   (beginnin args) "\n"
   (string-concatenate
    (map
     (lambda (rw)
       (string-append
        first-col-sep
        (string-join
         (map (lambda (entr) (string-append start-form entr end-form))
              (map mappin rw))
         col-sep)
        last-col-sep "\n"))
     lis))
   endin "\n"))

(define (tex-abbreviated-truth-table-beginning lngth)
  (string-append "\\begin{tabular}{|" (make-string lngth #\c) "|}\\hline"))

(define tex-abbreviated-truth-table-ending
  "\\hline\\end{tabular}\n")

(define tex-first-column-separator "")

(define tex-last-column-separator "\\\\")

(define tex-column-separator "&")

(define tex-start-formula "$")

(define tex-end-formula "$")

(define (tex-display-abbreviated-truth-table tabl)
  (display
   (process-abbreviated-truth-table-list
    tabl
    tex-abbreviated-truth-table-beginning
    tex-abbreviated-truth-table-ending
    tex-mapping
    tex-column-separator
    tex-start-formula
    tex-end-formula
    (length (first tabl))
    tex-first-column-separator
    tex-last-column-separator)))

(define (twiki-abbreviated-truth-table-beginning . unused)
  "%TABLE{databg=\"none\" tableframe=\"box\" tablerules=\"none\" }%")

(define twiki-abbreviated-truth-table-ending
  "\n")

(define twiki-column-separator "  |  ")

(define twiki-start-formula "%$")

(define twiki-end-formula "$%")

(define (twiki-display-abbreviated-truth-table tabl)
  (display
   (process-abbreviated-truth-table-list
    tabl
    twiki-abbreviated-truth-table-beginning
    twiki-abbreviated-truth-table-ending
    twiki-mapping
    twiki-column-separator
    twiki-start-formula
    twiki-end-formula)))

(define (utf-abbreviated-truth-table-beginning lngth) "")

(define utf-abbreviated-truth-table-ending
  "\n")

(define utf-column-separator "")

(define utf-start-formula "")

(define utf-end-formula "")

(define (utf-display-abbreviated-truth-table tabl)
  (display
   (process-abbreviated-truth-table-list
    tabl
    utf-abbreviated-truth-table-beginning
    utf-abbreviated-truth-table-ending
    utf-mapping
    utf-column-separator
    utf-start-formula
    utf-end-formula)))

(define (process-truth-function
         tabl beginnin endin mappin col-sep start-form end-form
         #!optional (args #f) (first-col-sep col-sep) (last-col-sep col-sep))
  (process-abbreviated-truth-table-list
   (map
    (lambda (rw) (append (first rw) (list (second rw))))
    tabl)
   beginnin endin mappin col-sep start-form end-form
   args first-col-sep last-col-sep))

(define (tex-truth-function-beginning lngth)
  (string-append "\\begin{tabular}{|" (make-string lngth #\c) "|c|}\\hline"))

(define (tex-display-truth-function tabl)
  (display
   (process-truth-function
    tabl
    tex-truth-function-beginning
    tex-abbreviated-truth-table-ending
    tex-mapping
    tex-column-separator
    tex-start-formula
    tex-end-formula
    (length (first (first tabl)))
    tex-first-column-separator
    tex-last-column-separator)))

(define (twiki-display-truth-function tabl)
  (display
   (process-truth-function
    tabl
    twiki-abbreviated-truth-table-beginning
    twiki-abbreviated-truth-table-ending
    twiki-mapping
    twiki-column-separator
    twiki-start-formula
    twiki-end-formula)))

(define (utf-display-truth-function tabl)
  (display
   (process-truth-function
    tabl
    utf-abbreviated-truth-table-beginning
    utf-abbreviated-truth-table-ending
    utf-mapping
    utf-column-separator
    utf-start-formula
    utf-end-formula)))

;;; Input functions: Take an input string of a deparenthesized statement form
;;; and convert it to a proper statement form, providing helpful error messages.
;;; Allow input of truth tables.

(define (get-string promp) ; 'read-line executes at the #\) and therefore
                                        ; reads the newline at the end of the command line.
                                        ; Use '(first-get get-string promp) for the first get-string.
  (display promp)
  (string-trim-both ; remove whitespace on the ends of the string
   (read-line)))

(define-macro (first-get get-comman promp) ; eats the newline at the end of the command
  `(begin
     (read-line)
     (,get-comman ,promp)))

(define (unsafe-get-symbol promp)
  (string->symbol
   (get-string promp)))

(define-macro (thunk fun)
  `(lambda () ,fun))

(define-macro (bound-global-symbol? symbl)
  `(if (symbol? ,symbl) ;test if symbl is a symbl
       (let* ((ceh (current-exception-handler)) ; copy the current exception handler
              (exception-handler ; define a new exception handler that returns #f
                                        ; instead of an error when an unbound-global-exception is raised
                                        ; and returns #t when there is a 'macro-used-as-variable exception,
                                        ; since the symbol is then bound to a macro
               (lambda (exc)
                 (cond ((unbound-global-exception? exc) #f)
                       ((and (expression-parsing-exception? exc)
                             (eq? (expression-parsing-exception-kind exc)
                                  'macro-used-as-variable)) #t)
                       (else (ceh exc))))))
         (with-exception-catcher
          exception-handler
          (thunk
           (let
               ((foo (eval ,symbl))) ;evaluate symbl to see if it is bound
             #t))))
       (error "*** ERROR IN bound-global-symbol?, not a symbol: " ,symbl)))

(define (get-symbol promp)
  (let ((symbl (first-get unsafe-get-symbol promp)))
    (let safe-symbl ((symbl symbl))
      (if (bound-global-symbol? symbl)
          (begin
            (let ((respons (get-string (string-append
                                        "*************\n"
                                        "Are you sure?\n"
                                        "'" (symbol->string symbl)
                                        " is already defined.\n"
                                        "Redefining some symbols can cause bad things\n"
                                        "to happen. If you are in doubt, respond no.\n\n"
                                        "Respond yes, no, q to quit, or <enter> for no.\n"
                                        "*************\n"
                                        "?? "))))
              (let chck ((respons respons))
                (cond
                 ((equal? respons "yes") symbl)
                 ((or (equal? respons "no") (equal? respons "")) (safe-symbl (unsafe-get-symbol promp)))
                 ((equal? respons "q") #f)
                 (else (chck (get-string "You must respond yes, no, <enter>, or q.\n?? ")))))))
          symbl))))

(define (statement-form-character? char)
  (or
   (char-set-contains? char-set:upper-case char)
   (char-set-contains? char-set:digit char)
   (member char '(#\( #\) #\space #\^ #\v #\- #\| #\< #\= #\>))))

(define (string->list-of-chars strin)
  (string-fold-right cons '() strin))

(define (string->statement-form-token-list strin)
                                        ; some basic sanity checks
  (and-let*
                                        ; strin is a string
   (((if (string? strin)
         #t
         (begin
           (display strin)
           (display " is not a string.\n")
           #f)))
                                        ; All characters are legal.
    ((apply-and (string-for-each (lambda (char)
                                   (if
                                    (statement-form-character? char)
                                    #t
                                    (begin
                                      (display char)
                                      (display " is not allowed in statement forms.\n")
                                      #f)))
                                 strin)))
                                        ; Parentheses are balanced.
    ((if (zero? (string-fold (lambda (char cnt)
                               (cond
                                ((eqv? char #\() (+ cnt 1))
                                ((eqv? char #\)) (- cnt 1))
                                (else cnt)))
                             0
                             strin))
         strin
         (begin
           (display "Unmatched parentheses.\n")
           #f))))
   (let tokeniz ((input-lis (string->list strin)) (output-lis '()))
     (cond
      ((null? input-lis) (reverse output-lis)) ; done
      ((eqv? (first input-lis) #\space) ; drop spaces
       (tokeniz (cdr input-lis) output-lis))
      ((memv (first input-lis) '(#\( #\) #\^ #\v)) ; one-character tokens
       (tokeniz (cdr input-lis) (cons (first input-lis) output-lis)))
      ((eqv? (first input-lis) #\-)
       (if (eqv? (second input-lis) #\|)
           (tokeniz (cddr input-lis) (cons "-|" output-lis))
           (begin
             (display "- must be followed by |.\n")
             #f)))
      ((eqv? (first input-lis) #\<)
       (if (and  (eqv? (second input-lis) #\=)  (eqv? (third input-lis) #\>))
           (tokeniz (cdddr input-lis) (cons "<=>" output-lis))
           (begin
             (display "< must be followed by =>\n")
             #f)))
      ((eqv? (first input-lis) #\=)
       (if (eqv? (second input-lis) #\>)
           (tokeniz (cddr input-lis) (cons "=>" output-lis))
           (begin
             (display "= must be followed by >\n")
             #f)))
      ((char-set-contains? char-set:upper-case (first input-lis))
       (receive (subscrip input-lis) (span (lambda (char) (char-set-contains? char-set:digit char)) (cdr input-lis))
         (tokeniz input-lis
                                        ; drop any numerical subscript from input-lis after removing the letter
                  (cons
                   (string-append (string (first input-lis))
                                  (apply string subscrip))
                   output-lis))))
      (else (display (list->string input-lis))
            (display " cannot end this statement form.\nDo you have a digit that is not part of a statement letter?\n")
            #f)))))

         ;;-- Main.ShaughanLavine - First posted version 10 Sep 2009 - Current version posted 7 Oct 2009
         ;;
Topic revision: r8 - 08 Oct 2009 - 03:22:46 - TWikiAdminGroup
  • ShaughanLavine - 18 Jan 2010 - 19:22 - 1.19 " class="twikiCurrentWebHomeLink twikiLink">web-bg-small Courses


 
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback