;===== ; CS 111 - Week 6 Lecture 1 - 2024-10-01 (require 2htdp/image) (require 2htdp/universe) ;===== ; some list-related definition- and function-reminders: ;===== ; DATA DEFINITION ; an Anything is an expression of any type ;===== ; DATA DEFINITION ; a list is one of: ; - empty ; - (cons Anything list) ; cons for CONStruct a list empty (cons "moo" empty) (cons 13 (cons "moo" empty)) ;----- ; signature: cons: Anything list -> list ; purpose: expects any expression (with a value) ; and a list, and returns a new list ; whose first value is that given expression ; and the rest of whose values are those ; of the given list (cons "howdy" (cons 13 (cons "moo" empty))) ;===== ; DATA DEFINITION: ; a NonEmptyList is one of: ; - (cons Anything empty) ; - (cons Anything NonEmptyList) ;----- ; signature: first: NonEmptyList -> Anything ; purpose: expects a non-empty list, and ; returns the first item in that list (first (cons 13 (cons "moo" empty))) ;----- ; signature: rest: NonEmptyList -> list ; purpose: expects a non-empty list, and ; returns a list of everything EXCEPT ; the first item in the given list ;**************************************** ; remember: rest ALWAYS returns a list!! ;***************************************** (rest (cons 13 (cons "moo" empty))) (rest (rest (cons 13 (cons "moo" empty)))) ;----- ; signature: empty?: Anything -> boolean ; purpose: expects any expression with a value, ; and returns whether it is an empty list (empty? "moo") (empty? (cons "haha" empty)) (empty? empty) ;----- ; signature: list?: Anything -> boolean ; purpose: expects any expression with a value, ; and returns whether it is a list (list? "moo") (list? (cons "haha" empty)) (list? empty) ;----- ; signature: length: list -> number ; purpose: expects a list, and returns ; the number of (top-level) items in ; the list (length empty) (length (cons 13 empty)) (length (cons 1 (cons 2 empty))) ;==== ; say I would like to "visit" each element in ; an argument list, but that list could be of ; ANY length ; let's develop a basic "template" for handling ; this ;===== ; so: based on a list's definition, it can be ; empty or not empty; ;===== ; THIS TEMPLATE IS NOT FINISHED YET!! ; ; (define (list-template ... a-list ...) ; (cond ; [(empty? a-list) ...] ; [else ...] ; ) ;===== ; and if the list is NOT empty -- ; we might find ourselves doing something ; to or based on the FIRST element in that non-empty ; list, ; and to or based on the REST of the elements in that ; non-empty list ;===== ; THIS TEMPLATE IS NOT FINISHED YET!! ; ; (define (list-template ... a-list ...) ; (cond ; [(empty? a-list) ...] ; [else (... (first a-list) ... ; (rest a-list) ...)] ; ) ; ) ;==== ; say I decide to write my own version of ; a function that just determines the top-level ; length of a given list ; I am calling it len (so it ah doesn't conflict with ; a certain built-in-function...) ;===== ; signature: len: list -> number ; purpose: expects any list, and returns the number ; of (top-level) elements in that list ;===== ; NEEEEEED to test at least the empty list case ; AND the non-empty-list case (check-expect (len empty) 0) (check-expect (len (cons 1 (cons 2 (cons 3 (cons 4 empty))))) 4) (define (len a-list) (cond [(empty? a-list) 0] [else (+ 1 (len (rest a-list)))] ) ) ;===== ; hey, function len above is calling itself!! ; * that's called a RECURSIVE function ; * when your data is self-referential, ; you may find that a recursive function is ; useful for acting on that data ; ; TWO FEATURES you WANNNNNNT for a "GOOD" recursive ; function: ; * have at LEAST one "base" case, ; a branch that does NOT have a recursive call in it ; * in each branch with a recursive call, ; make sure that recursive call has amongst its argument ; a "smaller" version of the original argument ; such that a "base" case must eventually be reached ;********************** ; THIS TEMPLATE IS NOW FINISHED!! ;********************** ; (define (list-template ... a-list ...) ; (cond ; [(empty? a-list) ...] ; [else (... (first a-list) ... ; (list-template ... (rest a-list) ...) ...)] ; ) ; ) ;===== ; BSL Racket has a file input/output module ; named 2htdp/batch-io (require 2htdp/batch-io) ;===== ; it has functions for simple file input/output ;===== ; one example: ;===== ; signature: read-lines: string -> list ; purpose: expects the name of a file written as a ; string - eitherits absolute/complete name or ; its name in the current working folder -- ; has the SIDE EFFECT of trying to open and read ; the contents of that file, ; and returns the contents read as a list of strings, ; one string per line in the given file ;===== ; NOTE: these won't work unless you have files ; with THESE names in the same folder as this ; .rkt file!! ; so, for posting purposes, I am commenting them out ; ;(read-lines "111lect06-1-PRE-CLASS.rkt") ;(read-lines "111lect06-1.rkt") ; ;(length (read-lines "111lect06-1-PRE-CLASS.rkt")) ;(len (read-lines "111lect06-1-PRE-CLASS.rkt")) ;===== ; ADDING AFTER CLASS: ; but this has the side-effect of WRITING to a file, ; creating it if it does not currently exist! (write-file "example-file.txt" "Hello, how are you?\nI am fine!\nWant to go grab\n a cuppa chai?") ;===== ; so these SHOULD work if you run this .rkt file! (read-lines "example-file.txt") (length (read-lines "example-file.txt")) (len (read-lines "example-file.txt")) ;===== ; another example of a function "walking through" a list ; ... how about one that adds 1 to each element in a list of ; numbers? ;==== ; signature: add1-list: list -> list ; purpose: expects a list of numbers, ; and returns a new list with each element of ; the given list increased by 1 ;===== ; again: be sure to include a test for an empty list ; argument, as well as at least one for a non-empty-list ; argument: (check-expect (add1-list empty) empty) (check-expect (add1-list (list 3 4 19 7)) (list 4 5 20 8)) (define (add1-list num-list) (cond [(empty? num-list) empty] [else (cons (+ 1 (first num-list)) (add1-list (rest num-list)))] ) ) (add1-list (list 3 4 19 7)) (add1-list (list 1 88 9 110 40 6 9000 25 4 9/2))