Reputation: 33
Im having an issue trying to use the map and filter in Racket for the following:
I'm representing a table of data using a struct, and I know I need to give that table to a map function to iterate through, and then filter the non-hardworker entries out for the final list, but I have no idea how to get the info I need out of my struct or how the map and filter should look...
This is what I have:
#lang racket
(struct worker (name work study ent))
(define workers(list
(worker '(bill) '(none) '(medium) '(none))
(worker '(jill) '(high) '(low) '(medium))
(worker '(tim) '(vhigh) '(none) '(vhigh))
(worker '(gary) '(medium) '(high) '(medium))
(worker '(samantha) '(vlow) '(vlow) '(medium))
(worker '(holly) '(vlow) '(low) '(low))
(worker '(ryan) '(low) '(low) '(low))
(worker '(quin) '(low) '(medium) '(vlow))
(worker '(lisa) '(medium) '(vlow) '(high))
(worker '(jennifer) '(low) '(low) '(vlow))
(worker '(jeff) '(high) '(low) '(high))
(worker '(george) '(medium) '(vhigh) '(medium))
(worker '(beth) '(none) '(none) '(low))
(worker '(maria) '(vlow) '(medium) '(low))
(worker '(simon) '(medium) '(high) '(high))
))
(define convert
(lambda (input)
(match (input
('none 0)
('vlow 1)
('low 2)
('medium 3)
('high 4)
('vhigh 5)
)
)
)
)
(define (hardworker workers)
(map(lambda(workers)...
Any help is appreciated.
Upvotes: 0
Views: 1296
Reputation: 2137
#lang racket
(require rackunit)
Note that since you're putting '( ... )
(quoted parenthesis) each field is a [Listof Symbol]
, instead of just symbols by themselves as represented in this answer. Each struct gives rise to "selector functions" which can extract values of fields.
(worker-ent (worker '(quin) '(low) '(medium) '(vlow)))
; => '(vlow).
(first '(vlow))
; => 'vlow.
If we were to represent the fields of the struct using just symbols, it would be:
(define workers
(list ; name work study ent
(worker 'bill 'none 'medium 'none)
(worker 'jill 'high 'low 'medium)
(worker 'tim 'vhigh 'none 'vhigh)
(worker 'gary 'medium 'high 'medium)
(worker 'samantha 'vlow 'vlow 'medium)
(worker 'holly 'vlow 'low 'low)
(worker 'ryan 'low 'low 'low)
(worker 'quin 'low 'medium 'vlow)
(worker 'lisa 'medium 'vlow 'high)
(worker 'jennifer 'low 'low 'vlow)
(worker 'jeff 'high 'low 'high)
(worker 'george 'medium 'vhigh 'medium)
(worker 'beth 'none 'none 'low)
(worker 'maria 'vlow 'medium 'low)
(worker 'simon 'medium 'high 'high)))
In fact it is wise to write down what each field represent along with their type:
(struct worker (name work study ent) #:transparent)
; A Worker is a (worker Symbol Amount Amount Amount)
; interpretation. name is the name of the worker, work, study and ent are
; the Amount that represents the work, study and entertainment done by the worker.
; Amount is one of
; - 'none
; - 'vlow
; - 'low
; - 'medium
; - 'high
; - 'vhigh
; interpretation. represents amount of something done.
convert
is putting the "Amount" enumeration into an order, however the syntax used for match
has problems. Here is a full definition with tests:
; convert : Amount -> Natural
; The ordering number of each Amount.
(define convert
(lambda (input)
(match input
['none 0]
['vlow 1]
['low 2]
['medium 3]
['high 4]
['vhigh 5])))
(check-equal? (convert 'none) 0)
(check-equal? (convert 'vlow) 1)
(check-equal? (convert 'low) 2)
(check-equal? (convert 'medium) 3)
(check-equal? (convert 'high) 4)
(check-equal? (convert 'vhigh) 5)
Note 1: We can avoid using match by using index-of
as follows:
(define (convert.v2 i)
(index-of '(none vlow low medium high vhigh) i))
(check-equal? (convert.v2 'none) 0)
(check-equal? (convert.v2 'vlow) 1)
(check-equal? (convert.v2 'low) 2)
(check-equal? (convert.v2 'medium) 3)
(check-equal? (convert.v2 'high) 4)
(check-equal? (convert.v2 'vhigh) 5)
To break the problem down, we need to know what it means for an Amount to be "at least High" and "no more than Medium" so we make the following predicates:
; at-least-high? : Amount -> Boolean
; is `a` at least High?
(define (at-least-high? a)
(>= (convert a) 4))
(check-false (at-least-high? 'none))
(check-false (at-least-high? 'vlow))
(check-false (at-least-high? 'low))
(check-false (at-least-high? 'medium))
(check-true (at-least-high? 'high))
(check-true (at-least-high? 'vhigh))
and
; no-more-than-medium? : Amount -> Boolean
; is `a` not more than Medium?
(define (no-more-than-medium? a)
(<= (convert a) 3))
(check-true (no-more-than-medium? 'none))
(check-true (no-more-than-medium? 'vlow))
(check-true (no-more-than-medium? 'low))
(check-true (no-more-than-medium? 'medium))
(check-false (no-more-than-medium? 'high))
(check-false (no-more-than-medium? 'vhigh))
Note 2: that we can simply check for members of the amount enumeration that are valid for our condition, in which case we wouldn't need convert
.
(define (at-least-high?.v2 a)
(or (symbol=? a 'high) (symbol=? a 'vhigh)))
(define (no-more-than-medium?.v2 a)
(or (symbol=? a 'none) (symbol=? a 'vlow)
(symbol=? a 'low) (symbol=? a 'medium)))
What does it mean for someone to be a hardworker? It's just the conjunction of the two predicates already defined:
; hardworker? : Worker -> Boolean
; Hard workers do at least high amount of work and
; have no more than medium amount of entertainment.
(define (hardworker? w)
(and (at-least-high? (worker-work w))
(no-more-than-medium? (worker-ent w))))
(check-true (worker 'bill 'none 'medium 'none))
(check-false (worker 'jill 'high 'low 'medium))
Note 3: If I had your definition of workers, I'd have to wrap (worker-work w)
and (worker-ent w)
with first
to extract the symbol out of the list.
Finally, the workers
list can be filter
ed using hardworker?
.
Note 4: We don't need map to iterate over the list, filter recurs over the list behind the scenes.
; hardworker : [List-of Worker] -> [List-of Worker]
; Only keep hard-workers.
(define (hardworker workers)
(filter hardworker? workers))
(check-equal? (hardworker workers) (list (worker 'jill 'high 'low 'medium)))
(check-equal? (hardworker (rest (rest workers))) empty)
We can consolidate everything into just one function using a lambda:
(define (hardworker.v2 workers)
(filter (λ (w) (and (member (worker-work w) '(high vhigh))
(member (worker-ent w) '(none vlow low medium))))
workers))
Upvotes: 3
Reputation: 702
#lang racket
(define-struct worker (name work study ent) #:transparent #:mutable)
(define workers-list
(list
(make-worker 'bill 'none 'medium 'none)
(make-worker 'jill 'high 'low 'medium)
(make-worker 'tim 'vhigh 'none 'vhigh)
(make-worker 'gary 'medium 'high 'medium)))
; work hard
(filter (lambda (w) (equal? 'high (worker-work w))) workers-list)
; not wrok hard
(filter (lambda (w) (not (equal? 'high (worker-work w)))) workers-list)
Upvotes: 0