[Cs254f11] Several questions

Lee Spector lspector at hampshire.edu
Mon Oct 3 20:48:35 EDT 2011


On Oct 3, 2011, at 6:20 PM, Wm. Josiah Erikson wrote:
> Then I am writing a function definition that gets passed a musical key, like "C" for instance, and I want to map it to the corresponding number, but I don't know how to use a string that contains the value of a key in a key-value pair and use it to get the value out of a map. I know how to do this:
> 
> (:C musical-keys)
> 
> But I want to be able to do something like this, assuming that my_song is a list of integers:
> (def song_key D)
> 
> (modified_truth (if (= (:song_key musical-keys) (first my_song)) 0.8)
> 
> Does this make any sense?
> 
> Thanks in advance,


I think I should try to unwind a couple of different things here, although the bottom line is a lot simpler than all of the stuff I'll explain first. That is, you can do what you want without this preamble, and I'll show you how, but for completeness I'm going to explain a few things.

One important point is that neither C nor :C is a string. C is a symbol and :C is a keyword. Those are different data types, and neither is a string. Both have names, which ARE strings, and these can be obtained using the "name" function:

(name 'C)

; "C"

(name :C)

; "C"

Note that I have to quote the symbol in the first example because otherwise it would try to evaluate it, and unless I had done something like (def C ...) it'd yell at me. And if I HAD done (def C ...) then (name C) would evaluate C and give me the result of calling name on the value that was given to C in its definition. You don't need to quote the :C in the second example because keywords (like numbers) evaluate to themselves. 

Here's part of the descriptions of keywords and symbols from http://clojure.org/data_structures:

---
Keywords
Keywords are symbolic identifiers that evaluate to themselves. They provide very fast equality tests. Like Symbols, they have names and optional namespaces, both of which are strings. The leading ':' is not part of the namespace or name.
---
Symbols
Symbols are identifiers that are normally used to refer to something else. They can be used in program forms to refer to function parameters, let bindings, class names and global vars. They have names and optional namespaces, both of which are strings. Symbols can have metadata (see with-meta).
---

If you look on that page you'll see a little more documentation, including the reason that both keywords and symbols can be used as functions to "look themselves up in" maps.

Back to your code:

The line in your code defining song_key is (def song_key D). 

That will try evaluate D, which I presume is not what you want. You could do (def song_key 'D) to put the symbol D in song_key, or (def song_key :D) to use a keyword. The latter is probably better since you're using keywords in your musical-keys map.

Now let's look at (modified_truth (if (= (:song_key musical-keys) (first my_song)) 0.8).

First I'm going to break it across lines and auto-format it:

(modified_truth (if (= (:song_key musical-keys) 
                     (first my_song)) 
                0.8)

Here (when I view it in clooj, or at least something with a monospaced font) I can see that "if" is being given two arguments -- the expression starting with -, and then 0.8. But it should take three: the condition, the thing to do/return if the condition is true, and the thing to do/return if the condition is false. It looks like you want the "if" to return 0.8 if the condition is true... but you should follow that with whatever you want it to return if it's false.

I think you intend your condition to ask "Is the number of the song's key equal to the first number in my_song?" You've expressed the second part correctly -- (first my_song) -- but your lookup in the map in the first part isn't right. Assuming that you did (def song_key :D) then the var song_key contains the keyword :D, and that's what you want to look up in the map. To do this -- to get the value out of a var and then look that up in the map -- you really want to use "get", as in:

(get musical-keys song_key)

; 2

I'm not sure what you intend with the surrounding call to modified_truth, so I'll stop there.

Bottom lines: 

- Use keywords, which always start with ":", for names that don't name values, but just themselves. You can use symbols for these kinds of things too, but keywords are handier because they don't have to be quoted.

- Use "get" to look computed things up in maps. The (:keyword map) shortcut works if you are looking up a keyword that you are hard-coding into your code -- and you can even do (map :keyword) if you like it better for some reason --  but "get" is often more clear and the better choice if the thing you're looking up is computed.

-Lee

--
Lee Spector, Professor of Computer Science
Cognitive Science, Hampshire College
893 West Street, Amherst, MA 01002-3359
lspector at hampshire.edu, http://hampshire.edu/lspector/
Phone: 413-559-5352, Fax: 413-559-5438



More information about the Cs254f11 mailing list