The Final Grade
7.8.0.1

The Final Grade

#lang typed/racket
(provide final-grade %)
 
 
(define-type Projects      (Pair Natural [Listof Assignment]))
(define-type Assignment    (Pair Exact-Rational Natural))
(define-type Presentations [Listof OK])
(define-type Panels        [Listof OK])
(define-type LabBooks      [Listof OK])
(define-type Percent       Real)
(define-type OK            (U 'ok+ 'ok 'ok- 'zero))
(define-type Ten           10)
 
 
(define (% {x : Real}) (/ x 100))
(define PROJECT      (% 60))
(define PRESENTATION (% 17))
(define PANEL        (% 17))
(define LAB          (%  9))
(define FINAL        (% 20))
(define ASSIGNMENTS  (% 80))
 
[define ok+  (% 99)]
[define ok   (% 90)]
[define ok-  (% 77)]
[define zero (% 42)]
 
 
(: final-grade (Projects Presentations Panels LabBooks -> Percent))
(define (final-grade projects presentations panels labs)
  (+ (* PROJECT      (project-grade projects))
     (* PRESENTATION (presentation-grade presentations))
     (* PANEL        (panel-grade panels))
     (* LAB          (lab-book-grade labs))
     (% 1)))
 
(: project-grade (Projects -> Percent))
(define (project-grade projects)
  (match-define (cons final-code-walk assignments) projects)
  (+ (* FINAL       (/ final-code-walk 10.0))
     (* ASSIGNMENTS (assignment-grades assignments))))
 
(: assignment-grades (-> [Listof Assignment] Percent))
(define (assignment-grades grades)
  (define-values (student-score max-score)
    (for/fold : (values Real Real)
      ([student-score 0.0][max-score 0])
      ([g : Assignment grades])
 
      (match-define (cons student max) g)
      (values (+ student-score student) (+ max-score max))))
  (/ student-score max-score))
 
(: okay-grades (-> [Listof OK] Percent))
(define (okay-grades oks)
  (/ (for/sum : Percent ((o : OK oks)) (grade-mapping o))
     (length oks)))
 
(: presentation-grade (Presentations -> Percent))
(define presentation-grade okay-grades)
 
(: panel-grade (Panels -> Percent))
(define panel-grade okay-grades)
 
(: lab-book-grade (LabBooks -> Percent))
(define lab-book-grade okay-grades)
 
(: grade-mapping (OK -> Percent))
(define (grade-mapping o)
  (cond
    [(eq? o 'ok+) ok+]
    [(eq? o 'ok)  ok]
    [(eq? o 'ok-) ok-]
    [(eq? o 'zero) zero]
    [else (error 'grade-mapping "unreachable code")]))
 
 
 
(module+ test
  (require typed/rackunit)
 
 
  (: perfect-projects Projects)
  (: perfect-final-walk Ten)
  (define perfect-final-walk    10)
  (define perfect-projects      (cons perfect-final-walk (list (cons 100 100))))
  (define value-projects        1.0)
  (define perfect-presentations '(ok+ ok+))
  (define value-presentations   (/ (+ ok+ ok+) 2))
  (define perfect-panels        '(ok+ ok+ ok+))
  (define value-panels          (/ (+ ok+ ok+ ok+) 3))
  (: perfect-labs LabBooks)
  (define perfect-labs          '(ok+))
  (define value-labs            1.0)
 
  (define perfect-grade
    (+ (* 3/5 value-projects)
       (* 17/100 value-presentations)
       (* 17/100 value-panels)
       (* 9/100 value-labs)
       (* 1/100)))
 
  (check-=
   (final-grade perfect-projects perfect-presentations perfect-panels perfect-labs)
   perfect-grade
   0.001))