Carlo,

See below.

On Tuesday, 8 April 2014 12:20:16 UTC+10, Carlo wrote:
>
> On Mon, Apr 07, 2014 at 04:08:03AM -0700, Peter West wrote: 
> > I'm trying to understand the difference between two alternatives in the 
> > following code that reads from a resource file. 
> > 
> > (defn vcf-res-reader 
> >   [res] 
> >   (->> res 
> >        io/resource 
> >        io/reader)) 
> > 
> > (defn lines-only 
> >   [varname prom resource] 
> >   (with-open [r (vcf-res-reader resource) 
> >               ; alternative 1 
> >               ;lineseq (line-seq r) 
> >               ] 
> >     ; alternative 2 
> >     (def lineseq (line-seq r)) 
> >     (eval `(def ~(symbol varname) lineseq)) 
> >     @prom)) 
> > 
> > (defn lazy-lines 
> >   [varname prom resource] 
> >   (future 
> >     (lines-only varname prom resource) 
> >     )) 
> > 
> > 
> > As the code stands, with alternative 2 enabled, the eval setting a named 
> > var to the value of "linseq" works as intended. However, if I disable 
> > alternative 2 and enable alternative 1, and I attempt to access the 
> named 
> > var ("cards" in this case), I get 
> > #<Unbound Unbound: #'vcf.core/cards> 
>
> You have a few problems with your code as it stands. I'll look at each 
> of the two alternatives separately. 
>
> First, alternative 1: 
>
> > (defn lines-only 
> >   [varname prom resource] 
> >   (with-open [r (vcf-res-reader resource) 
> >               lineseq (line-seq r)] 
> >     (eval `(def ~(symbol varname) lineseq)) 
> >     @prom)) 
>
> Your issue here is that the symbol "lineseq" in the eval form doesn't 
> have a name to refer to. You do have a local binding for lineseq, but 
> it's not visible to the eval: 
>
>   (let [x 10] (eval 'x)) ;=> Unable to resolve symbol: x 
>
> The lineseq binding should really be made in a "let", too, rather than a 
> with-open. The result of a line-seq can't be closed, so it's not really 
> sensible to put it in a "with-open". 
>

If that were the case, then the reference to "r" in alternative 2 "(def 
lineseq (line-seq r))" would not work; but it does, so "r" is in scope. 
Therefore, linseed from alternative 1 must also be in scope, mustn't it? 
 It was my understanding that the scope of with-open was equivalent to that 
of let in  that bindings were visible within the entire scope of the 
with-open.

>
> Now, on to alternative 2: 
>
> > (defn lines-only 
> >   [varname prom resource] 
> >   (with-open [r (vcf-res-reader resource)} 
> >     (def lineseq (line-seq r)) 
> >     (eval `(def ~(symbol varname) lineseq)) 
> >     @prom)) 
>
> This time, you do have something for "lineseq" to refer to! The "def" 
> special form has created a global binding for "lineseq". Now, at the top 
> level of your application you can lookup "lineseq" and get a value, but 
> this isn't good, because your function now modifies the global scope, 
> just to hold a temporary value. 
>

I agree entirely.  That's why i was trying to keep the "lineseq" var local 
to the with-open. I still don't know what's happening there. Unfortunately, 
I have another global (within the current namespace, at least) at the 
moment, and that is the named variable. The only other way I have seen to 
secrete the line-seq out without prematurely terminating it, is to define a 
read function within the body of the with-open, but that's even nastier, 
and it has timing problems.

>
>
>
>
> There are two ways for you to resolve this. What you're writing sounds a 
> little bit like it should be a macro, so you could write it as such: 
>
>   (defmacro lines-only [varname prom resource] 
>     `(with-open [r# (vcf-res-reader ~resource)] 
>        (let [lineseq# (line-seq r#)] 
>          (def ~(symbol varname) lineseq#) 
>          @~prom))) 
>
> (I think that's right, but I've not actually tested it.) 
>

I think this will run into the same problem, for reasons mentioned above. 

>
> Alternatively, you could write it as a function and use "intern": 
>
>   (defn lines-only [varname prom resource] 
>     (with-open [r (vcf-res-reader resource)] 
>       (let [lineseq (line-seq r)] 
>         (intern *ns* (symbol varname) lineseq) 
>         @prom))) 
>
> I'm less confident about this approach, but it should work. 
>
> All this being said: it's generally a bad idea to have a macro/function 
> modify the global scope without it being very clear that it's doing so. 
> I usually try to have my macro names start with "def" if they're 
> modifying the global scope (because they're "defining" something is my 
> logic). 
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to