Using Local Instead Of Helper Functions In Racket

Viewed 463

Problem

I'm given a list of lists of symbols and asked to manipulate it in a certain way, which I've already done (found in the definitions section), I want to convert this code from helper functions to local.

Definitions

The lists that I'm dealing with have their first element as an identifier and the rest of the list be descriptions of the item. For example, (list 'candy 'sweet 'light 'packaged). Note that every element is a symbol and that each list can have an infinite number of descriptions.

Given a list of these lists, I was asked to make a list that has all the descriptions of all the items, without duplicates. Order does not matter.

Examples

Here's a list that I created:

(list
 (list 'chips 'fresh 'crisp)
 (list 'oranges 'fresh 'sweet 'cold 'heavy)
 (list 'person 'tall)
 (list 'computer 'new 'heavy))

It is supposed to output (list 'fresh 'crisp 'sweet 'cold 'heavy 'tall 'new). Note that 'fresh does not appear twice, neither does heavy.

Code

; Main function
(define (get-desc lst) (remove-desc (add-list lst)))

; Function to process each individual list
(define (add-list lst)
  (cond [(empty? lst) empty]
        [else (append (add-row (rest (first lst))) (add-list (rest lst)))]))

; Process a single list, not nested
(define (add-row lst)
  (cond [(empty? lst) empty]
        [else (cons (first lst) (add-row (rest lst)))]))

; Removes duplicates in a list
(define (remove-desc lst)
  (cond [(empty? lst) empty]
        [else (cons (first lst) (remove-desc (filter (lambda (x) (not (symbol=? (first lst) x))) lst)))]))

So the code does what it is supposed to do. But how would I convert the helper functions into local? It is my first time trying to use local and I'm not very familiar with it. Is it even possible to fit all this into one function?

1 Answers

NB: Some teaching languages uses the special form local, however it does not say in the question that you are using any specific language so I'm assuming you are using #lang racket.

By moving them above the expression in the main function they become local to that function:

(define (get-desc lst) 
  ;; Function to process each individual list
  (define (add-list lst)
    (cond [(empty? lst) empty]
          [else (append (add-row (rest (first lst))) (add-list (rest lst)))]))

  ;; Process a single list, not nested
  (define (add-row lst)
    (cond [(empty? lst) empty]
          [else (cons (first lst) (add-row (rest lst)))]))

  ;; Removes duplicates in a list
  (define (remove-desc lst)
    (cond [(empty? lst) empty]
          [else (cons (first lst) (remove-desc (filter (lambda (x) (not (symbol=? (first lst) x))) lst)))]))

  ;; Lets get ready to rumble!
  (remove-desc (add-list lst)))

While not neccessary often you might not need to pass some variables when moving them inside another closure as the parameters of the main function will be available in the helpers unless they are shadowed by their own parameter with the same name. Eg.

(define (rmap proc lst)
  (rmap-helper proc lst '()))

(define (rmap-helper proc lst acc)
  (if (null? lst)
      acc
      (rmap-helper proc 
                   (cdr lst) 
                   (cons (proc (car lst)) acc))))

But when moving the implementation you can use the values that never change from the parent closure.

(define (rmap proc lst)
  (define (rmap-helper lst acc)
    (if (null? lst)
        acc
        (rmap-helper (cdr lst) 
                     (cons (proc (car lst)) acc))))

  (rmap-helper proc lst '()))
Related