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.