;; Prefix-String ::= " Prefix-Exp " ;; Prefix-List ::= ( Prefix-Exp ) ;; Prefix-Exp ::= Digit ;; ::= #\- Prefix-Exp Prefix-exp ;; Digit ::= #\0 | #\1 | #\2 | #\3 | #\4 ;; | #\5 | #\6 | #\7 | #\8 | #\9 ;; is-digit-char? : Char -> Bool ;; Returns true iff c is a Digit (define is-digit-char? (let ((digit-chars (string->list "0123456789"))) (lambda (c) (member c digit-chars)))) ;; is-prefix-string? : String -> Bool ;; Returns true iff contents of s conforms to Prefix-Exp grammar. (define is-prefix-string? (lambda (s) (is-prefix-list? (string->list s)))) ;; placeholder that should cause an error if it is ever invoked. (define is-prefix-list? (lambda (s) (you-need-to-choose-one-of-is-prefix-list?-v1-or-v2))) ;; is-prefix-list? : Listof[Char] -> Bool ;; Returns true iff x conforms to Prefix-List grammar. (define is-prefix-list?.v1 (lambda (l) (let ((after-exp (remove-one-prefix-exp l))) (null? after-exp)))) ;; remove-one-prefix-exp : Listof[Char] -> Listof[Char] or #f ;; If l starts with a Prefix-Exp, returns remaining contents of l following ;; the Prefix-Exp. Else returns #f. (define remove-one-prefix-exp (lambda (l) (cond ((null? l) #f) (else (cond ((is-digit-char? (car l)) (cdr l)) ((char=? #\- (car l)) (let* ((after-minus (cdr l)) (after-exp-1 (remove-one-prefix-exp after-minus)) (after-exp-2 (and after-exp-1 (remove-one-prefix-exp after-exp-1)))) after-exp-2)) (else #f)))))) ;; [[ see above header for contract and usage. ]] (define is-prefix-list?.v2 (lambda (l) (call-with-current-continuation (lambda (return-from-is-prefix-list) (null? (remove-one-prefix-exp/use-continuation l return-from-is-prefix-list)))))) ;; remove-one-prefix-exp/use-continuation : ;; Listof[Char] * (Boolean -> Nothing) -> Listof[Char] ;; If l starts with a Prefix-Exp, returns remaining contents of l following ;; the Prefix-Exp. Else invokes give-up. (define remove-one-prefix-exp/use-continuation (lambda (l give-up) (cond ((null? l) (give-up #f)) (else (cond ((is-digit-char? (car l)) (cdr l)) ((char=? #\- (car l)) (let* ((after-minus (cdr l)) (after-exp-1 (remove-one-prefix-exp/use-continuation after-minus give-up)) (after-exp-2 (remove-one-prefix-exp/use-continuation after-exp-1 give-up))) after-exp-2)) (else (give-up #f))))))) ;;; TESTS START HERE ;; test : Any X X (X X -> Boolean) -> unspecified (define test (lambda (name result expected) (cond ((not (equal? result expected)) (display "TEST FAILURE: ") (display name) (display " result: ") (display result) (display " should be: ") (display expected) (newline)) (else (display "test success: ") (display name) (newline))))) (test 'remove-1 (remove-one-prefix-exp '(#\2 #\3)) '(#\3)) (test 'remove-2 (remove-one-prefix-exp '(#\- #\2 #\1 #\4)) '(#\4)) (test 'remove-3 (remove-one-prefix-exp '(#\- #\- #\2 #\1 #\- #\9 #\5)) '()) (test 'plst?-0 (is-prefix-list? '()) #f) (test 'plst?-1 (is-prefix-list? '(#\1)) #t) (test 'plst?-2 (is-prefix-list? '(#\- #\- #\2 #\1 #\- #\9 #\5)) #t) (test 'plst?-3 (is-prefix-list? '(#\- #\- #\- #\2 #\1 #\- #\9 #\5 #\- #\1 #\- #\2 #\3)) #t) (test 'plst?-4 (is-prefix-list? '(#\- #\- #\- #\2 #\1 #\- #\9 #\5 #\- #\1 #\- #\2 #\3 #\6)) #f) (test 'plst?-5 (is-prefix-list? '(#\- #\n #\d)) ;; non-digit #f) (test 'pstr?-0 (is-prefix-string? "") #f) (test 'pstr?-1 (is-prefix-string? "1") #t) (test 'pstr?-2 (is-prefix-string? "--21-95") #t) (test 'pstr?-3 (is-prefix-string? "---21-95-1-23") #t) (test 'pstr?-4 (is-prefix-string? "---21-95-1-236") #f) (test 'pstr?-5 (is-prefix-string? "-nd") #f) ;; non-digit