(define recipe-name (lambda (recipe) (cadr (assoc 'name recipe)))) (define recipe-ingredients (lambda (recipe) (cadr (assoc 'ingredients recipe)))) (define recipe-steps (lambda (recipe) (cadr (assoc 'steps recipe)))) (define recipe-servings (lambda (recipe) (if (recipe-specifies-servings? recipe) (cadr (assoc 'servings recipe)) 1) )) (define ingredient-name (lambda (ingredient) (if (= (length ingredient) 2) (car (cdr ingredient)) (car (cddr ingredient))))) (define ingredient-amount (lambda (ingredient) (car ingredient))) (define ingredient-unit (lambda (ingredient) (if (= (length ingredient) 2) "" (car (cdr ingredient))))) ;; Predicates (define contains-ingredient? (lambda (search-ingredient recipe) (contains-ingredients? (list search-ingredient) recipe))) (define contains-ingredients? (lambda (search-ingredients recipe) (let ((ingredients (recipe-ingredients recipe))) (cond [(null? search-ingredients) #t] [(ingredient-by-name (car search-ingredients) ingredients) (contains-ingredients? (cdr search-ingredients) recipe)] [else #f]) ))) (define recipe-specifies-servings? (lambda (recipe) (assoc 'servings recipe))) ;; Searching and indexing (define ingredient-ref (lambda (ingredients n) (if (= n 0) (car ingredients) (ingredient-ref (cdr ingredients) (- n 1))))) (define ingredient-by-name (lambda (search-name ingredient-list) (let ((ingredient (car ingredient-list))) (cond [(equal? (ingredient-name ingredient) search-name) ingredient] [(null? (cdr ingredient-list)) #f] [else (ingredient-by-name search-name (cdr ingredient-list))])))) (define recipes-by-ingredients (lambda (search-ingredients recipes) (filter (lambda (x) (contains-ingredients? search-ingredients x)) recipes))) (define recipe-by-name (lambda (name recipes) (if (null? recipes) #f (let ((recipe (car recipes))) (if (equal? (recipe-name recipe) name) recipe (recipe-by-name name (cdr recipes))))))) ;; Manipulation (define scale-recipe-by-servings (lambda (wanted-servings recipe) (let ([name (recipe-name recipe)] [ingredients (recipe-ingredients recipe)] [steps (recipe-steps recipe)] [servings (recipe-servings recipe)]) (let ([new-name name] [new-ingredients (map (lambda (ingr) (cons (* (/ (car ingr) servings) wanted-servings) (cdr ingr))) ingredients)] [new-steps steps] [new-servings wanted-servings]) (make-recipe new-name new-servings new-ingredients new-steps) )))) (define scale-recipe-by-factor (lambda (scale-factor recipe) (let ([new-servings (* (recipe-servings recipe) scale-factor)]) (scale-recipe-by-servings new-servings recipe)))) ;; Constructors (define make-recipe (lambda (name servings ingredients steps) `((name ,name) (servings ,servings) (ingredients ,ingredients) (steps ,steps))))