#lang plai-typed ;; A line of packages is packed safely as long as ;; fragile packages are guarded by cushions, but it's ok ;; to have multiple fragile packages in a row. ;; A crate is hard on the outside, but must be packed ;; safely inside for the overall packaging to be safe. ;; To check for safe packging we need to "accumulate" ;; the kind of parcel that appears before. (define-type Parcel [fragile [weight : number]] [regular [weight : number]] [cushion] [crate [contents : (listof Parcel)]]) (module+ test (test (safe-package-after? (fragile 5) (fragile 5)) true) (test (safe-package-after? (fragile 5) (regular 5)) false) (test (safe-package-after? (fragile 5) (crate empty)) false) (test (safe-package-after? (fragile 5) (cushion)) true) (test (safe-package-after? (regular 5) (regular 6)) true) (test (safe-package-after? (cushion) (regular 7)) true) (test (safe-package-after? (crate empty) (regular 7)) true) (test (safe-package-after? (crate (list (fragile 8))) (regular 7)) true) (test (safe-package-after? (crate (list (fragile 8))) (cushion)) true) (test (safe-package-after? (crate (list (fragile 8) (regular 8))) (regular 8)) false)) (define (safe-package-after? [pkg : Parcel] [prev : Parcel]) (type-case Parcel pkg [fragile (weight) (or (fragile? prev) (cushion? prev))] [regular (weight) (not (fragile? prev))] [cushion () true] [crate (contents) (safe-packing? contents)])) ;(define (package-weight [pkg : Parcel]) ; (type-case Parcel pkg ; [fragile (weight) ...] ; [regular (weight) ...] ; [cushion () ...])) ; [crate (contents) ...(truck-weight contents)...])) ;; ---------------------------------------- ;; A list-of-parcel is either ;; - empty ;; - (cons parcel list-of-parcel) ;(define (truck-weight [t : (listof Parcel)]) ; (cond ; [(empty? t) ...] ; [(cons? t) ...(package-weight (first t)) ...(truck-weight (rest t))...])) ;; This is the function we want: (module+ test (test (safe-packing? empty) true) (test (safe-packing? (cons (fragile 55) (cons (regular 45) empty))) false) (test (safe-packing? (cons (fragile 55) (cons (cushion) (cons (regular 45) empty)))) true) (test (safe-packing? (list (regular 5) (cushion))) true)) ;; It's mostly implemented with a helper, which is why it doesn't ;; have the usual shape: (define (safe-packing? [t : (listof Parcel)]) (safe-packing-after? t (cushion))) (module+ test (test (safe-packing-after? empty (fragile 5)) true) (test (safe-packing-after? empty (regular 5)) true) (test (safe-packing-after? (cons (fragile 55) (cons (regular 45) empty)) (fragile 5)) false) (test (safe-packing-after? (cons (fragile 55) (cons (cushion) (cons (regular 45) empty))) (fragile 6)) true) (test (safe-packing-after? (cons (fragile 55) (cons (cushion) (cons (regular 45) empty))) (regular 6)) false) (test (safe-packing-after? (list (regular 5) (cushion)) (regular 7)) true)) (define (safe-packing-after? [t : (listof Parcel)] [prev : Parcel]) (cond [(empty? t) true] [(cons? t) (and (safe-package-after? (first t) prev) (safe-packing-after? (rest t) (first t)))]))