;=====
; CS 111 - Week 6 Lecture 1 - 2025-09-30

(require 2htdp/image)
(require 2htdp/universe)

;=====
; 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

;=====
; signature: cons: Anything list -> list
; purpose: expects any expression and a list,
;   and returns a new list with that expression's value
;   as its first element, and everything else in the given
;   list as the rest of the list

;=====
; 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 non-empty list

;=====
; signature: rest: NonEmptyList -> list
; purpose: expects a non-empty list, and returns the list
;    containing everything except the first element of the
;    given list (get it? it returns the REST of the given list)
;****************************************
; remember: rest ALWAYS returns a list!!
;*****************************************

;=====
; signature: empty?: Anything -> boolean
; purpose: expects any expression with a value, and returns
;     whether it is an empty list

;=====
; signature: list?: Anything -> boolean
; purpose: expects any expression with a value, and returns
;     whether it is of data type list

;=====
; signature: length: list -> number
; purpose: expects any list, and returns the number of
;    (top-level) elements in that list
;
; NOTE: in the list data definition, empty ends a list --
;     it is used to "mark" the end of a list, if you will;
;     the empty ending a list is NOT considered to be an element of
;     that list!

;=====
; START of an **INCOMPLETE** template for a function
;    "walking through" a list
;
; * see if the list is empty - if so, handle that empty list
; * otherwise, you know to handle a NON-empty list
;
;   (cond
;       [(empty? my-list) ...]
;       [else ...]
;   )

; for helping us COMPLETE this template,
; let's write our OWN version of length,
; say, len

;=====
; signature: len: list -> number
; purpose: expects any list, and returns the number of
;    top-level elements in that list

(check-expect (len empty) 0)

(check-expect (len (list 1 2 3 4 5 6 7 8)) 8)

(define (len a-list)
    (cond
        [(empty? a-list) 0]

        ; when a-list is not empty, add 1 (for the 1st element)
        ;     to the length of the *rest* o a-list

        [else (+ 1
                 (len (rest a-list)))]
    )
)

(len (list 1 "moo" #true "red" 21 null pi e))

;=====
; COMPLETED template for a function that "walks through a list
;
; (define (a-list-funct ... a-list ...)
;     (cond
;         [(empty? a-list) ...]
;         [else (...
;                  (first a-list) ...
;                  (a-list-funct ... (rest a-list) ...) ...)
;         ]
;     )
; )


;=====
; fun fact: DrRacket has a module 2htdp/batch-io

(require 2htdp/batch-io)

;-----
; 2htdp/batch-io has a selection of file input and file output functions
; (as would be needed for a so-called batch program, one with
;    no interactive input/output,
;    that reads its needed input from file(s) and writes its
;    resulting output to file(s)
;-----
; here is an example of one of its functions that reads from
;    a file:

;-----
; signature: read-lines: string -> list
; purpose: expects the name of a file written as a string --
;    either its full/"absolute" name OR its name in the current
;        working directory --
;    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,
;        each line in the file being one string in the result

(read-lines "111lect06-1.rkt")

; so, this essentially counts the number of lines in 111lect06-1.rkt!
;     (since read-lines returns a list of strings,
;         one string per line in the file,
;     and len counts the number of items in the list!)

(len (read-lines "111lect06-1.rkt"))

;-----
; signature: read-words: string -> list
; purpose: expects the name of a file written as a string --
;    either its full/"absolute" name OR its name in the current
;        working directory --
;    has the SIDE-EFFECT of trying to open and read the contents of
;        that file,
;    and returns the contents as a list of strings, with each
;        white-space-separated "token"/"word" being a string in this list

(read-words "111lect06-1.rkt")

; so, the length of the list that read-words returns is longer
;     than that returned by read-lines:

(len (read-words "111lect06-1.rkt"))

;=====
; len "walks through" a list to compute a number, here the
;     number of items in its argument list;
; some functions that "walk through" a list return a new list

;-----
; for example -- what if we would like a function to add 1 to
;     each number in a list of numbers?

;=====
; signature: add1-list: list -> list
; purpose: expects a list of numbers, and returns a list of numbers
;    in which each number is 1 larger than its counterpart in the
;    given list

(check-expect (add1-list empty)
              empty)

(check-expect (add1-list (list 10 20 30 40))
              (cons 11 (cons 21 (cons 31 (cons 41 empty)))))

(define (add1-list num-list)
     (cond
         ; there are no numbers in an empty list - so if num-list
         ;     is empty, just return an empty list
       
         [(empty? num-list) empty]

         ; but, if num-list is not empty, create a new list
         ;     from the result of cons-ing 1 + the first element in
         ;     num-list to the result of calling add1-list on the
         ;     rest of num-list
         
         [else (cons
                  (add1 (first num-list))
                  (add1-list (rest num-list)))
         ]
     )
)

(add1-list (list 10 20 30 40))