[Cs254f11] Variable scope issue

Wm. Josiah Erikson wjerikson at hampshire.edu
Thu Nov 17 13:29:20 EST 2011


OK, that works. I find the fact that a called function doesn't inherit 
the calling functions variables somewhat intuitive... I mean, actually, 
it would probably cause problems with variable scope if it did. The 
reason, clearly, that this didn't work for me, is that I was passing a 
variable NAME, not data, as you say. I didn't quite understand that at 
first, but it makes perfect sense.

So for anybody who is curious, create_function_map now looks like this:

(defn create_function_map
   "Returns a map where the keys are the functions in function-list
    and the values are what you get when you eval said function with 
song set to song"
   [song function-list]
   (zipmap function-list (map #((eval %) %2) function-list (repeat song))))

and my list of analysis functions (which gets passed as function-list to 
create_function_map) now looks like this:

(def list-of-analysis-functions '(std_dev_mostcom high_note low_note 
average_note average_real_note
                                       most_common_real_note 
least_common_real_note number_of_different_real_notes
                                       average_velocity 
percent_in_mixolydian percent_in_lydian percent_in_pentatonic
                                       percent_in_blues 
percentage_of_percussion percentage_of_pitchbend))

And everything works perfectly, without ever having to define song 
globally. Thank goodness. However, I still depend on term-map being 
defined globally and being redefined inside functions all the time, and 
would love your thoughts on how to get around that (though it works 
perfectly).

Thanks for the explanation, Lee.

     -Josiah



On 11/17/11 12:54 PM, Lee Spector wrote:
> You are right that you shouldn't have to def things inside of defs, and that there are cleaner, better ways to do what you want (see below). (Incidentally in 1.3 you'll be forced to declare vars as dynamic if you want to re-def them.)
>
> The reason that let doesn't work is indeed variable scope, as your message title implies. Let is lexically scoped, meaning that only code that appears within the textual body of the let form will be able to see the binding created by the let.
>
> But things can get pretty confusing when you're using eval and anything for which scope matters. The fact that (def song song) works for you is surprising and must mean that the two instances of "song" in there have different references, which must have something to do with the the implementation of def, which is a "special form".
>
> Much better than worrying about this sort of thing is to avoid the issue by eval-ing only the function names, to get the functions themselves, and passing the rest as evaluated data. For example:
>
> (defn foo [x] x)
>
> (defn bar [x] (inc x))
>
> (defn baz [x] (* 2 x))
>
> (def fns '(foo bar baz))
>
> (map #((eval %1) %2) fns (repeat 7))
>
> =>  (7 8 14)
>
> So in create_function_map you'd do something similar, not mapping eval down a list of expressions that include variable names, but rather evaluating just the function names, and using calling each of them on the input. Another way to do that:
>
> (let [actual-fns (map eval fns)]
>    (map apply actual-fns (repeat [7])))
>
> =>  (7 8 14)
>
> Here I evaluated all of the function names first and put the actual function objects (not the symbols that name them) in actual-fns. Then I mapped apply down the lists of functions and repeated copies of the full argument list for each application.
>
>   -Lee
>
>
>
>
> On Nov 17, 2011, at 11:47 AM, Wm. Josiah Erikson wrote:
>
>> So I'm rewriting my functions that create my globally-accessible map of functions to values per song. I'm rewriting them because I figured it was bad form to make them depend on "song" being set globally - rather I could pass the value of song to them, and that would be better style. That's all fine and dandy, except that the function I've written to create my global map doesn't seem to pass the value of song that it gets passed into it on to the functions that it calls:
>>
>> (defn create_function_map
>>   "Returns a map where the keys are the functions in function-list
>>    and the values are what you get when you eval said function with song set to song"
>>   [song function-list]
>>   (zipmap function-list (map eval (map #(list % 'song) function-list))))
>>
>> (defn create_terminal_map_vector
>>   "This takes a list of function names and a list of parsed songs, and returns a vector of maps.
>>    The maps have keys that are the function names and the values are the values that said functions
>>    return when song is set to the corresponding song in parsed-song-list"
>>   [function-list parsed-song-list]
>>   (vec(map create_function_map parsed-song-list (repeat function-list))))
>>
>> (def terminal-map (create_terminal_map_vector list-of-analysis-functions parsed_songs))
>>
>> That last def, which is what creates the data that everything else refers to, barfs because create_function_map (yes, I know, I could roll it into create_terminal_map_vector, and I probably will eventually, but it's easier to read this way for now) doesn't pass its value of song on to the "eval" call. If I just modify create_function_map so that it does a "def song song" before the zipmap, everything is fixed. I also tried a local "let", but that doesn't work either. Why? Clearly I'm missing something obvious. I shouldn't have to def things inside functions, right?
>>
>> Thanks in advance,
>>
>> -- 
>> Wm. Josiah Erikson
>> Network Engineer
>> Hampshire College
>> Amherst, MA 01002
>> (413) 559-6091
>>
>> _______________________________________________
>> Cs254f11 mailing list
>> Cs254f11 at lists.hampshire.edu
>> https://lists.hampshire.edu/mailman/listinfo/cs254f11
> --
> 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
>

-- 
Wm. Josiah Erikson
Network Engineer
Hampshire College
Amherst, MA 01002
(413) 559-6091



More information about the Cs254f11 mailing list