Fork me on GitHub

Does anyone here use proto repl with atom? I can't figure out how to turn it on. (derp)


@derpocious yes, how are you trying to turn it on?


@derpocious Did you follow Jason Gilman's "opinionated setup"? That's a really good place to start (although I recommend disabling the three auto-refresh options that it says enable -- at least until you're building everything with Stuart Sierra's Component 🙂 )


I go to package -> proto repl -> start repl


but the repl is always empty


RE: Defrecords I was reading through B&T and want to confirm that if I have code like this:

(defn event
  "Return a data type of `event`."
  [name start-time end-time]
    :name name
    :time { :start-time end-time
            :end-time start-time}})
Where an event is a data type in the domain I am working on that using a defrecord is the better choice as opposed to just building a map like I am doing above. CB&T would suggest this to be the case.


why would you use a record? just because it's a domain type isn't enough


Thats pretty much the only reason I can think of right now for the above scenario - really, trying to understand when they are used


typically a record is used when you need an immutable map and you also need to implement a protocol


(or interface, or more than one)


> when you need an immutable map I understand the protocol part, but what do you mean by the above? Isn't most everything immutable?


hash maps don't implement your protocols / interfaces


if by "everything" you mean all instances of () {} #{} {} [] - sure


it's not many types actually, we just re-use them a lot


if we didn't have defrecord, and you needed to make something implementing someone else's interface or protocol, and also wanted to use clojure's immutable data functions, you would have to do a lot of work to implement something that fit all those requirements


I'm stumped trying to get the same result from (pr (str g)) that I get from (pr g), where g is a record. From the docs, I'd have expected (str g) to expand to the contents of the record, but I get "[email protected]" instead. And I'm having a heck of a time trying to find the source for pr and friends, to figure out what they invoke to get those contents. Any pointers?


(It would be nice if e.g. actually explained how stringizing works....)


The only real reason I want str here is to avoid spaces in between arguments. I could use printf, but that has the same issue -- %s expands to the obscure object id, not the contents, of the object.


pr tries to print in a form that is readable


so if you give it a string, it prints something that will read as a string


if you want to combine without spaces, you can use pr-str with format


+user=> (format "%s%s" (pr-str {}) (pr-str "hello"))
or use str instead of pr-str to get the normal stringify (or equivalently let it implicitly use toString which is what str inokes)
+user=> (format "%s%s" (str {}) (str "hello"))
+user=> (format "%s%s" {} "hello")


@noisesmith -- ah, now I understand that pr-str is what I want, not str. They do different things for an instance of a record; pr-str prints the contents, str does not. Thanks!


Next q: is there a canonical way to handle frequently used pre/post-conditions so a) I don't have to keep writing out (say) four postconditions, and b) I still get the helpful message, upon violation, as to exactly which postcondition failed?


(I tried the macro approach, but of course that doesn't work, since a macro invocation can return only a single Sexpr....)


you can fix that with a data structure, the bigger problem is that macros only see data that is directly in the source, it can't know anything about the runtime data


@noisesmith -- do you have an example? I don't understand....


macros don't know anything about your data if it isn't literally in the source code (or put there by another macro first)


they run while compiling


Still not clear. What I'm looking for is a way to convert something like this, that occurs multiple times in my source code: :post [(cond1 ...) (cond2 ...) (cond3 ...) (cond4 ...)] to: :post [(common-code ...)] Now, if common-code is a function that returns the (and ...)of cond1 through cond2, it should work. But if the postcondition fails, the diagnostic will then only tell me that common-code returned false -- whereas, before, it'd tell me which of condN returned false. Does that make any sense?


(Typo: meant "...returns the (and ...) of cond1 through cond4.)


I know Lisp macros (well, at least Clojure macros) can only return a single sexpr -- so I'm just wondering whether there's any better way to tackle this (rather minor) issue.


OK - to make that work as a macro, you need to either use do (which gives you the same problem the common-code function had) or make a macro that generates an fn or defn form


(Maybe I'll get around to studying the Clojure source code for things like :post and come up with something myself?)


because you are generating input to a macro


Right, I assume some macro is getting :post and processing it somehow.


yes, the fn macro


which is a doozy


I can imagine!!


(defmacro fn
  "params => positional-params* , or positional-params* & next-param
  positional-param => binding-form
  next-param => binding-form
  name => symbol

  Defines a function"
  {:added "1.0", :special-form true,
   :forms '[(fn name? [params* ] exprs*) (fn name? ([params* ] exprs*)+)]}
  [& sigs]
    (let [name (if (symbol? (first sigs)) (first sigs) nil)
          sigs (if name (next sigs) sigs)
          sigs (if (vector? (first sigs)) 
                 (list sigs) 
                 (if (seq? (first sigs))
                   ;; Assume single arity syntax
                   (throw (IllegalArgumentException. 
                            (if (seq sigs)
                              (str "Parameter declaration " 
                                   (first sigs)
                                   " should be a vector")
                              (str "Parameter declaration missing"))))))
          psig (fn* [sig]
                 ;; Ensure correct type before destructuring sig
                 (when (not (seq? sig))
                   (throw (IllegalArgumentException.
                            (str "Invalid signature " sig
                                 " should be a list"))))
                 (let [[params & body] sig
                       _ (when (not (vector? params))
                           (throw (IllegalArgumentException. 
                                    (if (seq? (first sigs))
                                      (str "Parameter declaration " params
                                           " should be a vector")
                                      (str "Invalid signature " sig
                                           " should be a list")))))
                       conds (when (and (next body) (map? (first body))) 
                                           (first body))
                       body (if conds (next body) body)
                       conds (or conds (meta params))
                       pre (:pre conds)
                       post (:post conds)                       
                       body (if post
                              `((let [~'% ~(if (< 1 (count body)) 
                                            `(do [email protected]) 
                                            (first body))]
                                 [email protected](map (fn* [c] `(assert ~c)) post)
                       body (if pre
                              (concat (map (fn* [c] `(assert ~c)) pre) 
                   (maybe-destructured params body)))
          new-sigs (map psig sigs)]
        (if name
          (list* 'fn* name new-sigs)
          (cons 'fn* new-sigs))
        (meta &form))))


So it's "the fn macro" in more than one sense of "fn". 😉


Oh, well, that looks straightforward enough! 😉


Where does the code for that live, BTW? Now that I'm on my Windows 7 machine, instead of my Mac, I can't easily go to the source code (my CIDER environment tries to invoke unzip, which isn't installed ATM).


you can use clojure.repl/source to see it, and you can look at (System/getProperty "java.class.path") to see the jars you are using - the clojure source is in one of them


a jar is a zip file with a specific set of contents, which is why cider wants to use unzip


a more helpful trick:

+user=> ( "clojure/core.clj")
#object[ 0x47a5b70d "jar:file:/home/justin/bin/bench!/clojure/core.clj"]
the resource prints the path to the jar plus the path inside the jar, if it can find the resource


(I make an uberjar called "bench" for raw benchmarking containing clojure.jar plus my most commonly used libraries)


Okay, thanks! I had actually made a note about (clojure.repl/source map) awhile back, while reading "The Joy of Closure", and forgot I'd done that....


unless you interfere, clojure will refer clojure.repl in your starting namespace, so (source foo) will work


Okay. BTW, I can list the source for pr, but that source code calls pr-on, and this doesn't seem to work:

> (clojure.repl/source pr-on)
Source not found
;; => nil


it's private, it can't be seen unqualified from your ns


try (source clojure.core/pr-on)


Ah, of course, thanks again!