#lang racket

(require csc151)
(require racket/undefined)
(require rackunit)

;; CSC 151-01 (Spring 2021, Term 1)
;; Lab: Recursive Design (Side B)
;;   https://rebelsky.cs.grinnell.edu/Courses/CSC151/2021SpT1/code/labs/recursion-practice
;; Authors: YOUR NAMES HERE
;; Date: THE DATE HERE
;; Acknowledgements:
;;   ACKNOWLEDGEMENTS HERE

#|
In yesterday's lab, you practiced reading recursive procedures.  Today,
you will explore the construction of some recursive procedures.
|#

; +---------------+--------------------------------------------------
; | Supplied code |
; +---------------+

;;; (sum numbers) -> number?
;;;   numbers : listof number?
;;; Add all the numbers in a list together.
(define sum
  (lambda (numbers)
    (if (null? numbers)
        0
        (+ (car numbers) (sum (cdr numbers))))))

;;; (select-numbers values) -> listof? number
;;;   values : list?
;;; Select all the numbers in values, putting them into a new list.
(define select-numbers
  (lambda (values)
    (cond
      [(null? values)
       null]
      [(not (number? (car values)))
       (select-numbers (cdr values))]
      [else
       (cons (car values) (select-numbers (cdr values)))])))

;;; (count-value value values) -> integer?
;;;   value : any?
;;;   values : list?
;;; Count how many times value appears in values.
(define count-value
  (lambda (value values)
    (cond
      [(null? values)
       0]
      [(equal? value (car values))
       (+ 1 (count-value value (cdr values)))]
      [else
       (count-value (cdr values))])))

;;; (largest numbers) -> integer?
;;;   numbers : listof integer?
;;; Finds the largest number in a list
(define largest
  (lambda (numbers)
    (if (null? (cdr numbers))
        (car numbers)
        (max (car numbers) (largest (cdr numbers))))))

 
#| A |#

; +---------------------------------------------+--------------------
; | Exercise 1: Exploring recursive definitions |
; +---------------------------------------------+

; +-----------------------------+------------------------------------
; | Exercise 2: Counting values |
; +-----------------------------+

#| B |#

; +--------------------------------+---------------------------------
; | Exercise 3: Computing products |
; +--------------------------------+

#|
Write a recursive procedure, `(product nums)`, that computes the
product of a list of numbers. You should feel free to use `sum` as a
template for `product`. However, you should think carefully about the
base-case test and the base-case value.
|#

(define product
  (lambda (nums)
    -1))

; +--------------------------------------+---------------------------
; | Exercise 4: Counting with predicates |
; +--------------------------------------+

#|
The `length` procedure counts all the values in a list.  The `count-value` 
procedure counts how many time a supplied value appears in a list.  What 
if we want something in between the two: Rather than counting all the values,
we only want to count some of them, and rather than counting a single value,
we want to count all values matching a particular criterion?  (You may
think of this as `tally`.)
|#

#|
Document, write tests for, and implement a recursive procedure, 
`(tally-odd numbers)` that, given a list of integers, counts how
many are odd.

Note: You should not call list-length, length, filter, tally, or
count-value in your solution. Instead, use the ideas behind some
or all of these functions in crafting your own recursive solution.
|#

(define tally-odd
  (lambda (numbers)
    -1))

#| A |#

; +----------------------------+-------------------------------------
; | Exercise 5: Longer strings |
; +----------------------------+

#| B |#

; +-------------------------------+----------------------------------
; | Exercise 6: What comes first? |
; +-------------------------------+

#|
Document, write tests for, and implement a recursive procedure, 
`(alphabetically-first words)`, that finds the alphabetically first
string in a list of strings.

You can use `string-ci<=?` to compare any two strings for alphabetical 
order.

You may not use `sort` to solve this problem.
|#

(define alphabetically-first
  (lambda (words)
    ""))

#| AB |#

; +---------------------------+--------------------------------------
; | For those with extra time |
; +---------------------------+

#|
If you find that you have extra time and want to further explore some
of these issues, consider implementing any of the following procedures.
|#

; +--------------------------+---------------------------------------
; | Extra 1: Skipping values |
; +--------------------------+

#|
Document, write tests for, and write a procedure, `(find-first-skip lst)` 
that takes a list of symbols as a parameter and returns the index
of the first instance of the symbol `'skip` in `lst`, if `skip` appears
in `lst`, and false otherwise.

> (find-first-skip (list 'hop 'skip 'and 'jump))
1
> (find-first-skip (list 'skip 'hop 'jump 'skip 'and 'skip 'again))
0
> (find-first-skip (list 'hop 'to 'work 'jump 'to 'school 'but 'never 'skip 'class))
8
|#

(define find-first-skip
  (lambda (lst)
    #f))

; +--------------------------+---------------------------------------
; | Extra 2: Finding indices |
; +--------------------------+

#|
Document, write tests for, and implement a recursive procedure, 
`(find-index val lst)`, that takes a value and a list of values as
its parameters and returns the index of the first instance of val
in lst, if the value appears in the list. If the value does not
appear, find-index should return #f.
|#

(define find-index
  (lambda (val lst)
    #f))

; +-------------------------+----------------------------------------
; | Extra 3: Riffling lists |
; +-------------------------+

#|
Document, write tests for, and implement a recursive proceure,
(riffle first second) that produces a new list containing alternating
elements from the lists first and second. If one list runs out
before the other, then the remaining elements should appear at the
end of the new list.

> (riffle (list 'a 'b 'c) (list 'x 'y 'z))
(a x b y c z)
> (riffle (list 'a 'b 'c) (range 0 10))
(a 0 b 1 c 2 3 4 5 6 7 8 9)
|#

(define riffle
  (lambda (first second)
    null))
