[Cs254f11] Several questions

Lee Spector lspector at hampshire.edu
Tue Oct 4 11:33:29 EDT 2011


On Oct 4, 2011, at 10:55 AM, Wm. Josiah Erikson wrote:

> Alrighty, so this is awesome, and makes sense, and is fine, but I can move on with my life and just write this darn thing, thanks!

Awesome is awesome.


> However, in the future, I would think that I would want to take input from the user, and say "What key do you want your song to be in?" and a user would enter "C", not ":C". Is there no way to look up a value in a map with its key without telling clojure it's a key by prepending it with ":" ?

Actually anything can be a key in a map. People often use keywords as map keys just because they're handy (don't need quoting, they let you use that shortcut "look myself up" syntax for lookups, etc) but you can use numbers or symbols or even lists, vectors, etc. as keys in a map. Here's a map with a bunch of different kinds of keys:

(def m {1 "one", 'two "magoo", :three "tee hee" [4 4] "and more"})

; #'user/m

(get m 1)

; "one"

(get m 'two)

; "magoo"

(get m :three)

; "tee hee"

(get m [4 4])

; "and more"

With keywords and symbols you can do the special "call as it it's a function but instead look myself up in a map" thing if you want to:

(:three m)

; "tee hee"

('two m)

; "magoo"

But you don't have to do any of that if it confuses you. And it won't work with other kinds of keys:

(1 m)

; #<CompilerException java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)>

That error means that it's trying to call 1 as a function, no good. Or worse:

([4 4] m)

; #<CompilerException java.lang.IllegalArgumentException: Key must be integer (NO_SOURCE_FILE:0)>

That's a bizarre error message that comes from the fact that another weird shortcut lets you index into a vector with an integer, and this thinks that you're trying to index into [4 4] with m rather than the other way around! But it's pretty goofy and if you're using vectors as keys (which is pretty odd) then just use get to access the map.

And you can *always* use get. The "look myself up" thing is concise and if you're using keywords for your map keys, which is often done, then it works nicely. But get will always work and will sometimes be more clear.

BTW when you say "take input from the user" a flag goes up in my mind because Java (not Clojure per se) makes terminal I/O weirdly harder than it ought to be, so I'd avoid it for now. Put your input in your code or in a file and life will be easier, at least while you develop the computational core of your project, and if you really want to make a console app then we can talk about ways to do that.


> I can get down with having to define the value of a variable by quoting it... I guess.
> No other language that I've worked with requires you to do that, but whatever. 

Most of the languages with which you're probably familiar don't have a symbol data type at all, and also don't have a way to evaluate/execute code that is being handled as data. So the issue doesn't arise. In lisp you can treat code as data, in which case you don't want to run it (yet), you just want to put it in a variable or pass it to a function or process it in some other way. And maybe evaluate it later, or maybe not (since it could really just be data in some cases, but code and data are made out of the same stuff). You want some code to be evaluated and some not to be, so you have to have a way of telling the system which is which. 

Within a body of code you do want to evaluate most stuff, so we mark the stuff that we don't want evaluated, by preceding it with a single quote. (Or, btw, by surrounding it with (quote ...) -- "quote" is a special form, and perhaps the most pure and important one in some sense.) If you say (get my-map foo) then foo will be evaluated as code, which is exactly what you want if you've defined foo as a variable holding some value that you want to look up as a key in my-map. But if you want to look up the symbol foo itself then you have to tell it to treat foo as data (a symbol), not as code. So you'd say (get my-map 'foo). Or if you use keywords as the keys in your map, like :foo, then you can do (get my-map :foo). That :foo WILL be evaluated, but keywords evaluate to themselves.

> By I really can't look up something in a map without prepending it with a ":" ? Is there no way to do:
> 
> (def song_key 'C)
> 
> and then look it up in a map? I have to:
> 
> (def song_key :C)
> (get musical-keys song_key)

I'm a little confused (let me know if this isn't clear yet) but I think you can do whatever you want here as long as you use the same key in both parts; either use 'C in both cases or :C in both cases.


> and why does this appear do the same thing:
> 
> (def song_key ':C)

What you've got there is a quoted keyword; an exotic specimen, since keywords evaluate to themselves and so there's rarely (ever?) a need to quote them. But it fact the quote says "don't evaluate this thing" and the thing is a keyword so you get the keyword. But since keywords evaluate to themselves you can just say :C and it's the same thing.

> 
> I'd think there would be some way for me to stick the ":" in while I'm looking it up, but the obvious ways don't seem to work:
> 
> josiah.sandbox=>
> (get musical-keys :song_key)
> nil

This is looking up the keyword :song_key -- it's not evaluating song_key, which would give you the symbol C.

> 
> josiah.sandbox=>
> (get musical-keys ':song_key)
> nil

That's the same as the above; another of those exotic quoted keyword specimens.

> 
> I clearly still don't get it :) Thanks for your patience.

Let me know if you still don't!

 -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