git @ Cat's Eye Technologies TPiS / master util.scm
master

Tree @master (Download .tar.gz)

util.scm @masterraw · history · blame

;
; util.scm - miscellaneous utility procedures
; Total Procedures in Scheme, May 2006, Chris Pressey
; For license information, see the file LICENSE in this directory.
;

;
; Determine if a Scheme datum is acyclic.
;
(define acyclic?
  (lambda (pair)
    (acyclic-test pair '())))

(define acyclic-test
  (lambda (pair acc)
    (cond
      ((not (pair? pair))
        #t)
      ((memq pair acc)
        #f)
      (else
        (let ((fst     (car pair))
              (snd     (cdr pair))
              (new-acc (cons pair acc)))
          (and (acyclic-test fst new-acc) (acyclic-test snd new-acc)))))))

;
; XXX explain and/or borrow eopl:error
;
(define-total error
  (lambda (msg)
    (display msg) (newline)
    (read '())))

;
; Test case for test suite.
;
(define-syntax test
  (syntax-rules ()
    ((test test-name expr expected)
      (begin
        (display "Running test: ") (display (quote test-name)) (display "... ")
        (let ((result expr))
          (cond
            ((equal? result expected)
              (display "passed.") (newline))
            (else
              (display "FAILED!") (newline)
              (display "Expected: ") (display expected) (newline)
              (display "Actual:   ") (display result) (newline))))))))

;
; XXX there may be a problem doing NON-TAIL (self-)recursion, check it out.
;
(define-total bindings->names
  (lambda (bindings)
    (if (acyclic? bindings)
       (cond
         ((null? bindings)
           '())
         (else
           (let* ((binding (car bindings))
                  (rest    (cdr bindings))
                  (name    (car binding)))
             (cons name (bindings->names rest))))))))

(define-total bindings->values
  (lambda (bindings)
    (if (acyclic? bindings)
       (cond
         ((null? bindings)
           '())
         (else
           (let* ((binding (car bindings))
                  (rest    (cdr bindings))
                  (value   (cadr binding)))
             (cons value (bindings->values rest))))))))

(define-total is-lambda?
  (lambda (expr-rep)
    (and
      (pair? expr-rep)
      (eq? 'lambda (car expr-rep)))))

(define-total is-let?
  (lambda (expr-rep)
    (and
      (pair? expr-rep)
      (eq? 'let (car expr-rep)))))

(define-total is-let*?
  (lambda (expr-rep)
    (and
      (pair? expr-rep)
      (eq? 'let* (car expr-rep)))))

(define-total is-if?
  (lambda (expr-rep)
    (and
      (pair? expr-rep)
      (eq? 'if (car expr-rep)))))

(define-total is-cond?
  (lambda (expr-rep)
    (and
      (pair? expr-rep)
      (eq? 'cond (car expr-rep)))))

(define-total is-begin?
  (lambda (expr-rep)
    (and
      (pair? expr-rep)
      (eq? 'begin (car expr-rep)))))

(define-total is-call?
  (lambda (expr-rep)
    (and
      (pair? expr-rep)
      (not (eq? (car expr-rep) 'quote)))))  ;... and all others

(define-total is-identifier?
  (lambda (expr-rep)
    (symbol? expr-rep)))

(define-total is-quote?
  (lambda (expr-rep)
    (and
      (pair? expr-rep)
      (eq? 'quote (car expr-rep)))))