[Cs254f11] Variable scope issue

Lee Spector lspector at hampshire.edu
Thu Nov 17 12:54:20 EST 2011


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



More information about the Cs254f11 mailing list