Suggestions for state modification improvements in this bit of code?

81 views
Skip to first unread message

Dave Tenny

unread,
Nov 30, 2013, 6:17:01 PM11/30/13
to clo...@googlegroups.com
I'm still learning clojure and wrote this decidedly unfunctional bit of code as part of a common lisp style DESCRIBE function.

I was wondering what experienced clojure-ers  (what's the proper reference?) might suggest to make this function less ugly.

I realize making a purely functional version of this is probably the clojure thing to do, but it wasn't worth my time,
nor did I think it would make the code shorter (correct me if I'm wrong).

Anyway, with regard to mutable state is there a more concise and/or preferred way to do this?

The function in question is just querying the many maps of a namespace to yield another map with some interpretations of the namespace with respect to a given symbol.  I am struggling with some of the capabilities of namespaces and so this was just a bit of learning code for me, though I have to say my resulting DESCRIBE function has been really useful to me.  At some point when it's not a total embarrassment perhaps I'll post it.

Thanks for your suggestions:

(defn ns-symbol-relationship
  "Return a map of entries that describe the relationship of a symbol to a given namespace."
  [ns symbol]
  (if (not (symbol? symbol))
    (throw (Exception. (str "ns-symbol-relationship expected symbol, got " symbol))))
  ;; ns-name ns-aliases ns-imports ns-interns ns-map ns-publics ns-refers
  (with-local-vars [result (transient {})]
    (when (= (ns-name ns) symbol)        ;ns-name gives a symbol
      (var-set result (assoc! (var-get result) :names-ns ns))) ;symbol names namespace
    ; ns-aliases gives a map, but the k/v types/semantics are presently unknown
    (doseq [[k v] (seq (ns-aliases ns))]
      (when (= k symbol)
        (var-set result (assoc! (var-get result) :alias-for v)))
      (when (= v symbol)
        (var-set result (assoc! (var-get result) :aliased-by k))))
    ;; ns-imports keyed by symbol, valued by class
    (if-let [v (get (ns-imports ns) symbol)]
      (var-set result (assoc! (var-get result) :imports v)))       ;symbol names imported class
    ;; ns-interns gives a map, keys are symbols in the namespace, values are vars( and special forms?)
    ;; that they map to. 
    (if-let [v (get (ns-interns ns) symbol)]
      (var-set result (assoc! (var-get result) :interns v)))
    ;; ns-maps gives a map, value types/semantics are unknown
    (if-let [v (get (ns-map ns) symbol)]
      (var-set result (assoc! (var-get result) :maps-to v)))
    ;; ns-publics gives a map of public intern mappings, presumably a subset of ns-interns
    (if-let [v (get (ns-publics ns) symbol)]
      (var-set result (assoc! (var-get result) :interns-publicly v)))
    ;; ns-refers gives a map of refer-mappings, value semantics unknown
    (if-let [v (get (ns-refers ns) symbol)]
      (var-set result (assoc! (var-get result) :refers-to v)))
    (persistent! (var-get result))))

Thomas

unread,
Nov 30, 2013, 6:33:49 PM11/30/13
to clo...@googlegroups.com

On Saturday, November 30, 2013 11:17:01 PM UTC, Dave Tenny wrote:

I'm still learning clojure and wrote this decidedly unfunctional bit of code as part of a common lisp style DESCRIBE function.

I was wondering what experienced clojure-ers  (what's the proper reference?) 

Clojurians ;)

Thomas 

Dave Tenny

unread,
Nov 30, 2013, 6:49:29 PM11/30/13
to clo...@googlegroups.com
What, not conj!urers?


--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/gbg1ABsbT-I/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Sean Grove

unread,
Nov 30, 2013, 7:41:08 PM11/30/13
to clojure
Dave, I may not have totally understood the original function, but here are a few possible implementations, each moving towards what I would think of as being simpler: https://www.refheap.com/21379

It could of course be made more efficient and slightly cleaner, but maybe it's a start.

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 clojure+u...@googlegroups.com.

Dave Tenny

unread,
Dec 1, 2013, 9:18:20 AM12/1/13
to clo...@googlegroups.com
Wow, lots of good tips, thanks.    I'm still digesting some of the finer bits.

Observations:

- The refheap pastebin link was useful for future code posts.
- The :pre/:post conditions pointer was good, I vaguely new of them, but hadn't used them.
- The as-> form was new (and useful) to me.  In general I'm still struggling to fit -> and friends into my style.
- I found the #4 variant easiest to read, didn't even occur to me to do such a thing, coming from common lisp I'm still trying to get used to [], {}, #{} options.  Unfortunately #4 also added the most undesired entries to the map (see question below).

Questions:

- The only problem with the variants is that they introduce nil valued entries in the map where my original function only added map entries if the namespace relationships existed, I'd like to preserve that.  Presumably I could add an "assoc-if" or similar type thing to avoid adding nil valued entries. Maybe clojure already has such a construct?  My preference is to avoid adding them in the first place, rather than filtering them from the map in a post-construction operation.

- 'pr-str' almost seems redundant with 'str', but I suppose it observes pretty printing guidelines where str would not?  Any significant nuances here, or are these two functions largely redundant?

- Your many suggestions certainly seem preferable to my state based approach, but for my edification, what is the optimal way to implement a state based approach in this example?  I wasn't sure about my use of vars versus, say, atoms, or other clojure constructs for mutable state.  Just looking for suggestions here.

Thanks again, really useful stuff!
Reply all
Reply to author
Forward
0 new messages