I'm trying to turn 'red into 2, 'white into 9, 'brown into 1, and so on.
My code starts like this: (define (sum-of-colours colour1 colour2 colour3 ...)
I want the user to input symbols such as 'red, 'yellow, or 'black into colour1, colour2, etc... and then all the corresponding values get added up. Based on my current knowledge, I can't think of a way to directly turn symbols into numbers. Could someone give a hint about what should I do? Greatly appreciated!
A classic lispy approach would be to use an association list to associate color symbols with numbers. An association list is a sort of dictionary which is itself a list of pairs to be associated. For example:
(define my-colors '((red 2)
(white 9)
(brown 1)))
Now one can get at the correct pair using the assoc
function:
scratch.rkt> (assoc 'red my-colors)
'(red 2)
The number itself can be retrieved by using second
on this result; but it is better to write an accessor function so that the implementation details of the dictionary can be changed without breaking code that uses the color dictionary. Further, using second
directly on the result of assoc
may fail since an input color symbol may not exist in the dictionary. This definition returns #f
when a color symbol is not found:
(define (get-color c)
(let ((entry (assoc c my-colors)))
(if entry
(second entry)
#f)))
In Racket you could also use a hash table for this (other lisps have hash tables, too):
(define my-color-table (hash 'red 2
'white 9
'brown 1))
Now if you redefine get-color
to make use of the new dictionary representation, other code that uses get-color
will continue to work so long as the new definition preserves the interface:
(define (get-color c)
(hash-ref my-color-table c #f))
The hash-ref
function allows a failure-result to be specified; here when a key is not found, #f
is returned, as before. This could be useful in a sum-colors
function:
(define (sum-colors cs)
(apply + (remove* '(#f)
(map get-color cs))))
Note that sum-colors
does not care how the color dictionary is implemented, only that get-color
knows how to retrieve color numbers from color symbols. Here, map
is used to map the input list of color symbols to a list of color numbers. When a color symbol is not found, that symbol maps to #f
in the list of color numbers. remove*
is used to remove all instances of #f
before summing the list using apply
. There are of course other ways to write this, and you may want some behavior other than to ignore unknown color symbols in the input.
Sample REPL interaction:
scratch.rkt> (sum-colors '(red brown))
3
scratch.rkt> (sum-colors '(red white purple green))
11