#lang racket ;; The following incantation loads the testing library, which includes ;; check-expect and generate-report. (require htdp/testing) ;; File: a01.rkt ;; Author: Robert Keller and ;; Assignment 1 Freebies ;; TBD indicates a definition you need to provide (among possibly others) (define TBD null) ;; The first definition is a freebie. It happens that it uses ;; recursion, which is not to be used for your part of the assignment. ;; You can pretend that it is built-in ;; Given a list, non-empty-suffixes returns the list of non-empty suffixes ;; of that list, largest to smallest. ;; For example, (non-empty-suffixes '(1 2 3)) returns '((1 2 3) (2 3) (3)). (define (non-empty-suffixes List) (if (null? List) null (cons List (non-empty-suffixes (rest List))))) ;; Rationale: The empty list has no proper non-empty suffixes. ;; A non-empty list has itself followed by the non-empty suffixes of its rest ;; as its non-empty-suffixes. (check-expect (non-empty-suffixes '(1 2 3 4)) '((1 2 3 4) (2 3 4) (3 4) (4))) (check-expect (non-empty-suffixes '(1 2 3)) '((1 2 3) (2 3) (3))) (check-expect (non-empty-suffixes '(1 2)) '((1 2) (2))) (check-expect (non-empty-suffixes '(1)) '((1))) ;; Given a list, non-full-prefixes returns the list of the prefixes of that list, ;; other than the list itself, in the order smallest to largest. ;; For example, (non-full-prefixes '(1 2 3 4)) returns '(() (1) (1 2) (1 2 3)). (define (non-full-prefixes List) (cons '() (reverse (rest (map reverse (non-empty-suffixes (reverse List))))))) ;; Rationale: Make use of function non-empty-suffixes, which is provided ;; The non-full-prefixes of a list are the reverses of non-empty suffixes ;; of the the list in reverse, excluding the entire list, but adding the ;; empty list. (check-expect (non-full-prefixes '(1 2 3 4)) '(() (1) (1 2) (1 2 3))) (check-expect (non-full-prefixes '(1 2 3)) '(() (1) (1 2))) (check-expect (non-full-prefixes '(1)) '(())) ;; is-true converts the argument to a pure Boolean (#t or #f) value. ;; This is useful for the case that some test such as member ;; returns a list rather than just #t, especially if we are ;; giving the result to check-expect for comparison and don't ;; want to spell out the exact result. (define (is-true value) (if value #t #f)) (check-expect (member #\c (string->list "abcde")) (string->list "cde")) (check-expect (is-true (member #\c (string->list "abcde"))) #t) (check-expect (is-true (member #\z (string->list "abcde"))) #f) ;; titles4 is a list of titles as given in the assignment handout (define titles4 (list "It is easier to fight for one's principles than to live up to them." "The only normal people are the ones you don't know very well." "Love thy neighbor as thyself, but choose your neighborhood." "The covers of this book are too far apart." "No good deed goes unpunished." "I either want less corruption, or more chance to participate in it." "My opinions may have changed, but not the fact that I am right." )) ;; Define punctuation to be a list of punctuation characters (define punctuation (string->list ".,;:!?")) (check-expect punctuation '(#\. #\, #\; #\: #\! #\?)) ;; Define a set of noise words (define noise4 (map symbol->string '(a am and are as but either for in is it of on or the than that this to too))) ;; is-stopword determines whether Word is in the list StopWords (define (is-stopword Word StopWords) TBD) (check-expect (is-true (is-stopword "the" noise4)) #t) (check-expect (is-true (is-stopword "The" noise4)) #t) (check-expect (is-true (is-stopword "apple" noise4)) #f) (check-expect (is-true (is-stopword "Apple" noise4)) #f) ;; Function mappend expects a function returning a list and a list. ;; It returns a list consisting of the results of the function ;; applied to each element of the list appended together into a single list. (define (mappend Function List) TBD) ;; For testing mappend (define (zeroTo X) (range 0 (+ 1 X))) (check-expect (zeroTo 5) '(0 1 2 3 4 5)) (check-expect (mappend zeroTo '(1 2 3)) '(0 1 0 1 2 0 1 2 3)) (check-expect (mappend zeroTo '(3)) '(0 1 2 3)) (check-expect (mappend zeroTo '()) '()) ;; Given a list, all-cleaves returns the list of all ways of cleaving the ;; list into a non-full prefix and a non-empty suffix. ;; For example, (all-cleaves '(1 2 3 4)) returns ;; '((() (1 2 3 4)) ;; ((1) (2 3 4)) ;; ((1 2) (3 4)) ;; ((1 2 3) (4))) (define (all-cleaves List) TBD) (check-expect (all-cleaves '(1 2 3)) '((() (1 2 3)) ((1) (2 3)) ((1 2) (3)))) (check-expect (all-cleaves '(1 2 3 4)) '((() (1 2 3 4)) ((1) (2 3 4)) ((1 2) (3 4)) ((1 2 3) (4)))) (check-expect (all-cleaves '(1)) '((() (1)))) ;; ends-with-char is #t if String ends with ;; one of the characters in List-of-chars (define (ends-with-char String List-of-chars) TBD) (check-expect (is-true (ends-with-char "foobar" '(#\r))) #t) (check-expect (is-true (ends-with-char "foobar" '(#\f))) #f) ;; Given a non-empty list, all-but-last returns the list of all ;; but the last element. It is an error to call it on an empty list. ;; For example, (all-but-last '(1 2 3 4)) returns '(1 2 3). (define (all-but-last List) TBD) (check-expect (all-but-last '(1 2 3 4)) '(1 2 3)) (check-expect (all-but-last '(1)) '()) (check-error (all-but-last '())) ;; Given a non-empty string, string-all-but-last returns the string of all ;; but the last character. It is an error to call it on an empty string. (define (string-all-but-last String) TBD) (check-expect (string-all-but-last "foobar") "fooba") (check-expect (string-all-but-last "f") "") (check-error (string-all-but-last "")) ;; Given a list of strings, split-strings returns a list of lists ;; wherein each list consists of the individual words in an original string, ;; where words are understood to be separated by one or more spaces. ;; This relies on the built-in function string-split. (define (split-strings Titles) TBD) (check-expect (split-strings '("The rain in Spain" "falls mainly in the plain" "The quick brown fox" "just plays with my very lazy dog")) '(("The" "rain" "in" "Spain") ("falls" "mainly" "in" "the" "plain") ("The" "quick" "brown" "fox") ("just" "plays" "with" "my" "very" "lazy" "dog"))) (check-expect (split-strings '()) '()) (check-expect (split-strings '("foo bar")) '(("foo" "bar"))) (check-expect (split-strings '("foo" "bar")) '(("foo") ("bar"))) ;; Given a list of lists, tag-elements returns a list of lists, each consisting ;; of the index of the original inner list (starting from 0) ;; followed by the elements of the list itself. ;; For example, (tag-elements '((a) (b c d) (e f)) returns '((0 a) (1 b c d) (2 e f)). (define (tag-elements splits) TBD) (check-expect (tag-elements '((a) (b c d) (e f))) '((0 a) (1 b c d) (2 e f))) (check-expect (tag-elements '((a))) '((0 a))) (check-expect (tag-elements '()) '()) ;; Given a list consisting of a tag followed by some more lists, ;; distribute-tag returns a list of lists, wherein each of the original lists ;; is tagged with the tag. ;; For example, (distribute-tag '(123 (a b) (c d) (e f))) ;; returns '((123 a b) (123 c d) (123 e f)). (define (distribute-tag List) TBD) (check-expect (distribute-tag '(123 (a b) (c d) (e f))) '((123 a b) (123 c d) (123 e f))) (check-expect (distribute-tag '(123 (a b))) '((123 a b))) (check-expect (distribute-tag '(123 ())) '((123))) (check-expect (distribute-tag '(123)) '()) ;; Given a list of lists, all-tagged-cleaves returns the list of ;; all cleaves of the inner lists, with each cleave tagged with ;; the index of the inner lists position. ;; For example (all-tagged-cleaves '((a b) (c d e f) (g h i))) returns ;; '((0 () (a b)) ;; (0 (a) (b)) ;; ;; (1 () (c d e f)) ;; (1 (c) (d e f)) ;; (1 (c d) (e f)) ;; (1 (c d e) (f)) ;; ;; (2 () (g h i)) ;; (2 (g) (h i)) ;; (2 (g h) (i))) (define (all-tagged-cleaves ListOfLists) TBD) (check-expect (all-tagged-cleaves '((a b) (c d e f) (g h i))) '((0 () (a b)) (0 (a) (b)) (1 () (c d e f)) (1 (c) (d e f)) (1 (c d) (e f)) (1 (c d e) (f)) (2 () (g h i)) (2 (g) (h i)) (2 (g h) (i)))) (check-expect (all-tagged-cleaves '((c d e f))) '((0 () (c d e f)) (0 (c) (d e f)) (0 (c d) (e f)) (0 (c d e) (f)))) (check-expect (all-tagged-cleaves '()) '()) ;; create-kwic-index creates a list of triples representing the kwic index ;; from any list of strings. (define (create-kwic-index Noise Punctuation Titles) TBD) ;; Simple test case for create-kwic-index (define noise1 '("the" "to" "is" "it" "thy")) (define titles1 (list "It is easier to fight." "The only normal people." "Love thy neighbor." )) (check-expect (create-kwic-index noise1 punctuation titles1) '((0 "It is" "easier to fight.") (0 "It is easier to" "fight.") (2 "" "Love thy neighbor.") (2 "Love thy" "neighbor.") (1 "The only" "normal people.") (1 "The" "only normal people.") (1 "The only normal" "people."))) ;; Other test cases, some commented out until needed (define noise2 '("the" "of" "a")) (define titles2 '( "Who Cares?" "They All Laughed" "Somebody From Somewhere" "A Foggy Day" "Clap Yo' Hands" "Stiff Upper Lip" "Strike Up The Band" "Soon" "Bidin' My Time" "Aren't You Kind Of Glad We Did?" "Of Thee I Sing" "The Half Of It, Dearie' Blues" )) ;(check-expect (create-kwic-index noise2 punctuation titles2) ;'((1 "They" "All Laughed") ; (9 "" "Aren't You Kind Of Glad We Did?") ; (6 "Strike Up The" "Band") ; (8 "" "Bidin' My Time") ; (11 "The Half Of It, Dearie'" "Blues") ; (0 "Who" "Cares?") ; (4 "" "Clap Yo' Hands") ; (3 "A Foggy" "Day") ; (11 "The Half Of It," "Dearie' Blues") ; (9 "Aren't You Kind Of Glad We" "Did?") ; (3 "A" "Foggy Day") ; (2 "Somebody" "From Somewhere") ; (9 "Aren't You Kind Of" "Glad We Did?") ; (11 "The" "Half Of It, Dearie' Blues") ; (4 "Clap Yo'" "Hands") ; (10 "Of Thee" "I Sing") ; (11 "The Half Of" "It, Dearie' Blues") ; (9 "Aren't You" "Kind Of Glad We Did?") ; (1 "They All" "Laughed") ; (5 "Stiff Upper" "Lip") ; (8 "Bidin'" "My Time") ; (10 "Of Thee I" "Sing") ; (2 "" "Somebody From Somewhere") ; (2 "Somebody From" "Somewhere") ; (7 "" "Soon") ; (5 "" "Stiff Upper Lip") ; (6 "" "Strike Up The Band") ; (10 "Of" "Thee I Sing") ; (1 "" "They All Laughed") ; (8 "Bidin' My" "Time") ; (6 "Strike" "Up The Band") ; (5 "Stiff" "Upper Lip") ; (9 "Aren't You Kind Of Glad" "We Did?") ; (0 "" "Who Cares?") ; (4 "Clap" "Yo' Hands") ; (9 "Aren't" "You Kind Of Glad We Did?"))) ;(check-expect (create-kwic-index noise4 punctuation titles4) ;'((3 "The covers of this book are too far" "apart.") ; (3 "The covers of this" "book are too far apart.") ; (5 "I either want less corruption, or more" "chance to participate in it.") ; (6 "My opinions may have" "changed, but not the fact that I am right.") ; (2 "Love thy neighbor as thyself, but" "choose your neighborhood.") ; (5 "I either want less" "corruption, or more chance to participate in it.") ; (3 "The" "covers of this book are too far apart.") ; (4 "No good" "deed goes unpunished.") ; (1 "The only normal people are the ones you" "don't know very well.") ; (0 "It is" "easier to fight for one's principles than to live up to them.") ; (6 "My opinions may have changed, but not the" "fact that I am right.") ; (3 "The covers of this book are too" "far apart.") ; (0 "It is easier to" "fight for one's principles than to live up to them.") ; (4 "No good deed" "goes unpunished.") ; (4 "No" "good deed goes unpunished.") ; (6 "My opinions may" "have changed, but not the fact that I am right.") ; (6 "My opinions may have changed, but not the fact that" "I am right.") ; (5 "" "I either want less corruption, or more chance to participate in it.") ; (1 "The only normal people are the ones you don't" "know very well.") ; (5 "I either want" "less corruption, or more chance to participate in it.") ; (0 "It is easier to fight for one's principles than to" "live up to them.") ; (2 "" "Love thy neighbor as thyself, but choose your neighborhood.") ; (6 "My opinions" "may have changed, but not the fact that I am right.") ; (5 "I either want less corruption, or" "more chance to participate in it.") ; (6 "" "My opinions may have changed, but not the fact that I am right.") ; (2 "Love thy" "neighbor as thyself, but choose your neighborhood.") ; (2 "Love thy neighbor as thyself, but choose your" "neighborhood.") ; (4 "" "No good deed goes unpunished.") ; (1 "The only" "normal people are the ones you don't know very well.") ; (6 "My opinions may have changed, but" "not the fact that I am right.") ; (0 "It is easier to fight for" "one's principles than to live up to them.") ; (1 "The only normal people are the" "ones you don't know very well.") ; (1 "The" "only normal people are the ones you don't know very well.") ; (6 "My" "opinions may have changed, but not the fact that I am right.") ; (5 "I either want less corruption, or more chance to" "participate in it.") ; (1 "The only normal" "people are the ones you don't know very well.") ; (0 "It is easier to fight for one's" "principles than to live up to them.") ; (6 "My opinions may have changed, but not the fact that I am" "right.") ; (0 "It is easier to fight for one's principles than to live up to" "them.") ; (2 "Love" "thy neighbor as thyself, but choose your neighborhood.") ; (2 "Love thy neighbor as" "thyself, but choose your neighborhood.") ; (4 "No good deed goes" "unpunished.") ; (0 "It is easier to fight for one's principles than to live" "up to them.") ; (1 "The only normal people are the ones you don't know" "very well.") ; (5 "I either" "want less corruption, or more chance to participate in it.") ; (1 "The only normal people are the ones you don't know very" "well.") ; (1 "The only normal people are the ones" "you don't know very well.") ; (2 "Love thy neighbor as thyself, but choose" "your neighborhood.")) ;) ;; The following is for a visual check, to see that the part after the ;; gap is truly in alphabetic order. ;(check-expect ; (map (lambda (X) (list (first X) (third X) (second X))) ; (create-kwic-index noise4 punctuation titles4)) ; '((3 "apart." "The covers of this book are too far") ; (3 "book are too far apart." "The covers of this") ; (5 "chance to participate in it." "I either want less corruption, or more") ; (6 "changed, but not the fact that I am right." "My opinions may have") ; (2 "choose your neighborhood." "Love thy neighbor as thyself, but") ; (5 "corruption, or more chance to participate in it." "I either want less") ; (3 "covers of this book are too far apart." "The") ; (4 "deed goes unpunished." "No good") ; (1 "don't know very well." "The only normal people are the ones you") ; (0 "easier to fight for one's principles than to live up to them." "It is") ; (6 "fact that I am right." "My opinions may have changed, but not the") ; (3 "far apart." "The covers of this book are too") ; (0 "fight for one's principles than to live up to them." "It is easier to") ; (4 "goes unpunished." "No good deed") ; (4 "good deed goes unpunished." "No") ; (6 "have changed, but not the fact that I am right." "My opinions may") ; (6 "I am right." "My opinions may have changed, but not the fact that") ; (5 "I either want less corruption, or more chance to participate in it." "") ; (1 "know very well." "The only normal people are the ones you don't") ; (5 "less corruption, or more chance to participate in it." "I either want") ; (0 "live up to them." "It is easier to fight for one's principles than to") ; (2 "Love thy neighbor as thyself, but choose your neighborhood." "") ; (6 "may have changed, but not the fact that I am right." "My opinions") ; (5 "more chance to participate in it." "I either want less corruption, or") ; (6 "My opinions may have changed, but not the fact that I am right." "") ; (2 "neighbor as thyself, but choose your neighborhood." "Love thy") ; (2 "neighborhood." "Love thy neighbor as thyself, but choose your") ; (4 "No good deed goes unpunished." "") ; (1 "normal people are the ones you don't know very well." "The only") ; (6 "not the fact that I am right." "My opinions may have changed, but") ; (0 "one's principles than to live up to them." "It is easier to fight for") ; (1 "ones you don't know very well." "The only normal people are the") ; (1 "only normal people are the ones you don't know very well." "The") ; (6 "opinions may have changed, but not the fact that I am right." "My") ; (5 "participate in it." "I either want less corruption, or more chance to") ; (1 "people are the ones you don't know very well." "The only normal") ; (0 "principles than to live up to them." "It is easier to fight for one's") ; (6 "right." "My opinions may have changed, but not the fact that I am") ; (0 "them." "It is easier to fight for one's principles than to live up to") ; (2 "thy neighbor as thyself, but choose your neighborhood." "Love") ; (2 "thyself, but choose your neighborhood." "Love thy neighbor as") ; (4 "unpunished." "No good deed goes") ; (0 "up to them." "It is easier to fight for one's principles than to live") ; (1 "very well." "The only normal people are the ones you don't know") ; (5 "want less corruption, or more chance to participate in it." "I either") ; (1 "well." "The only normal people are the ones you don't know very") ; (1 "you don't know very well." "The only normal people are the ones") ; (2 "your neighborhood." "Love thy neighbor as thyself, but choose")) ; ) ;; Begin formatting procedures. These are best left as is. ;; format maps function format-triple over an entire list of triples. (define (format left right triples) (map (lambda (triple) (format-triple left right triple)) triples)) ;; format-triple shapes the contents of a triple to fit a ;; given number of spaces on the left and right, and adds a newline character at the end. (define (format-triple left right triple) (string-append (fit-left left (second triple)) " " (fit-right right (third triple)) " : " (number->string (first triple)) "\n" )) ;; (fit-left space string) puts string into the allocated amount of space on the left side (define (fit-left space string) (let ((length (string-length string))) (if (<= length space) (pad-left (- space length) string) (chop-left space string)))) ;; (fit-right space string) puts string into the allocated amount of space on the right side (define (fit-right space string) (let ( (length (string-length string))) (if (<= length space) (pad-right (- space length) string) (chop-right space string)))) ;; (pad-left space string) pads string with blanks on the left. (define (pad-left space string) (string-append (make-string space #\space) string)) ;; (pad-right space string) pads string with blanks on the right. (define (pad-right space string) (string-append string (make-string space #\space))) ;; (chop-right space string) chops a string on the right to a given amount of space. (define (chop-right space string) (substring string 0 space)) ;; (chop-left space string) chops a string on the left to a given amount of space. (define (chop-left space string) (string-reverse (substring (string-reverse string) 0 space))) ;; string-reverse reverses a string (define (string-reverse string) (list->string (reverse (string->list string)))) (check-expect (pad-right 20 "a long string") "a long string ") (check-expect (chop-right 5 "a long string") "a lon") (check-expect (fit-right 5 "a long string") "a lon") (check-expect (fit-right 20 "a long string") "a long string ") ;; Below are tests of both format and create-kwic-index functions. ;(check-expect (format 10 20 ; (create-kwic-index noise1 '() titles1)) ; ;'(" It is easier to fight. : 0\n" ; " easier to fight. : 0\n" ; " Love thy neighbor. : 2\n" ; " Love thy neighbor. : 2\n" ; " The only normal people. : 1\n" ; " The only normal people. : 1\n" ; "nly normal people. : 1\n")) ;(check-expect (format 30 40 (create-kwic-index noise2 punctuation titles2)) ;'( ;" They All Laughed : 1\n" ;" Aren't You Kind Of Glad We Did? : 9\n" ;" Strike Up The Band : 6\n" ;" Bidin' My Time : 8\n" ;" The Half Of It, Dearie' Blues : 11\n" ;" Who Cares? : 0\n" ;" Clap Yo' Hands : 4\n" ;" A Foggy Day : 3\n" ;" The Half Of It, Dearie' Blues : 11\n" ;" Aren't You Kind Of Glad We Did? : 9\n" ;" A Foggy Day : 3\n" ;" Somebody From Somewhere : 2\n" ;" Aren't You Kind Of Glad We Did? : 9\n" ;" The Half Of It, Dearie' Blues : 11\n" ;" Clap Yo' Hands : 4\n" ;" Of Thee I Sing : 10\n" ;" The Half Of It, Dearie' Blues : 11\n" ;" Aren't You Kind Of Glad We Did? : 9\n" ;" They All Laughed : 1\n" ;" Stiff Upper Lip : 5\n" ;" Bidin' My Time : 8\n" ;" Of Thee I Sing : 10\n" ;" Somebody From Somewhere : 2\n" ;" Somebody From Somewhere : 2\n" ;" Soon : 7\n" ;" Stiff Upper Lip : 5\n" ;" Strike Up The Band : 6\n" ;" Of Thee I Sing : 10\n" ;" They All Laughed : 1\n" ;" Bidin' My Time : 8\n" ;" Strike Up The Band : 6\n" ;" Stiff Upper Lip : 5\n" ;" Aren't You Kind Of Glad We Did? : 9\n" ;" Who Cares? : 0\n" ;" Clap Yo' Hands : 4\n" ;" Aren't You Kind Of Glad We Did? : 9\n") ; ) ;; display-kwic-index creates, formats, and displays the kwic-index from a list of Titles (define (display-kwic-index Left Right Stopwords Punctuation Titles) (display (format Left Right (create-kwic-index Stopwords Punctuation Titles)))) (display-kwic-index 30 35 noise4 punctuation titles4) (generate-report)