2015-10-31
| 00:27 | pyon | Let's say that (foo bar) returns a list. How do I instead return a lazy sequence, with the same contents as foo bar? |
| 00:28 | justin_smith | (lazy-seq (foo bar)) - but there is little advantage to this, the real advantage is to generating your result lazily |
| 00:28 | pyon | Well, in my case (foo bar) is actually a recursive call. |
| 00:28 | pyon | Wait, just in case - `map` itself returns a lazy sequence, right? |
| 00:28 | justin_smith | then instead of (cons h (foo arg)) do (lazy-seq (cons h (foo arg))) inside the body of foo |
| 00:29 | justin_smith | sure, map returns a lazy-seq |
| 00:32 | pyon | What I really want to delay is the recursive call itself. |
| 00:32 | pyon | Rather than a cons. |
| 00:33 | justin_smith | you need cons to construct the list |
| 00:33 | justin_smith | the lazy-seq will delay all evaluation inside it |
| 00:35 | pyon | In this situation, I'm almost sure that what needs to be delayed is the recursive call itself: https://www.refheap.com/111230 |
| 00:36 | justin_smith | pyon: like I said, lazy-seq in that position delays both the cons and the recursive call |
| 00:36 | amalloy | it's easier to just wrap the whole body of the function in lazy-seq |
| 00:36 | amalloy | but you can indeed put it just about anywhere and it'd be fine |
| 00:36 | justin_smith | fair point |
| 00:37 | pyon | :-O |
| 00:37 | justin_smith | so yeah, like amalloy says, you can just do (defn mono [k xs] (lazy-seq (when-let ...))) |
| 00:56 | jhn | why does (merge-with concat {} {:a [1]}) => {:a [1]} |
| 00:56 | jhn | but (swap! (atom {}) merge-with concat {:a [1]}) => |
| 00:56 | jhn | IllegalArgumentException contains? not supported on type: clojure.core$concat |
| 00:59 | amalloy | because that's (merge-with {} concat ...) |
| 01:00 | jhn | ah! that makes sense. ty. :) |
| 01:03 | jhn | is this the least ugly way to make this work? |
| 01:03 | jhn | (swap! (atom {}) #(merge-with concat % {:a [1]})) |
| 01:05 | pyon | Why is lazy-seq called lazy-*seq*, if it can be used on things other than sequences? |
| 01:05 | jhn | because seq is the name of the interface. |
| 01:05 | jhn | so you can use it with anything that is a seq |
| 01:07 | jhn | essentially, the "things other than sequences" you're referring to *are* actually sequences. |
| 01:12 | mungojelly | everything is everything and programming is just an extended meditation on how similar everything is to everything else |
| 01:21 | pyon | jhn: Ah! |
| 01:21 | pyon | Is there any way to delay computations that don't yield (the beginning of) a sequence? |
| 01:22 | rhg135 | defer |
| 01:22 | pyon | Ah! |
| 01:22 | rhg135 | Err, delay |
| 01:23 | rhg135 | ,(def v (delay (println *clojureversion*))) |
| 01:23 | clojurebot | #error {\n :cause "Unable to resolve symbol: *clojureversion* in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: *clojureversion* in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve... |
| 01:24 | rhg135 | ,(def v (delay (println *clojure-version*))) |
| 01:24 | clojurebot | #'sandbox/v |
| 01:24 | rhg135 | ,@v |
| 01:24 | clojurebot | {:major 1, :minor 8, :incremental 0, :qualifier alpha3}\n |
| 03:28 | pyon | Is there anything like a recursive macroexpand? |
| 03:29 | pyon | That is, macroexpand everything. Or, even better, only macroexpand specific macros that I tell it to expand. |
| 03:45 | TEttinger | pyon: yeah |
| 03:46 | TEttinger | http://clojure.github.io/clojure/clojure.walk-api.html#clojure.walk/macroexpand-all |
| 03:47 | TEttinger | ,(clojure.walk/macroexpand-all (if (and true "yay") :hooray :boo)) |
| 03:47 | TEttinger | ,(clojure.walk/macroexpand-all (if (and true "yay") :hooray :boo))) |
| 03:47 | clojurebot | #error {\n :cause "clojure.walk"\n :via\n [{:type java.lang.ClassNotFoundException\n :message "clojure.walk"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run "URLClassLoader.java" 366]\n [java.net.URLClassLoader$1 run "URLClassLoader.java" 355]\n [java.security.AccessController doPrivileged "AccessController.java" -2]\n [java.net.U... |
| 03:47 | clojurebot | #error {\n :cause "clojure.walk"\n :via\n [{:type java.lang.ClassNotFoundException\n :message "clojure.walk"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run "URLClassLoader.java" 366]\n [java.net.URLClassLoader$1 run "URLClassLoader.java" 355]\n [java.security.AccessController doPrivileged "AccessController.java" -2]\n [java.net.U... |
| 03:47 | TEttinger | ,(require '[clojure.walk]) |
| 03:47 | clojurebot | nil |
| 03:47 | TEttinger | ,(clojure.walk/macroexpand-all (if (and true "yay") :hooray :boo)) |
| 03:47 | clojurebot | :hooray |
| 03:47 | TEttinger | ,(clojure.walk/macroexpand-all '(if (and true "yay") :hooray :boo)) |
| 03:47 | clojurebot | (if (let* [and__4224__auto__ true] (if and__4224__auto__ "yay" and__4224__auto__)) :hooray :boo) |
| 03:49 | pyon | TEttinger: Ah, nice, thanks. :-) |
| 03:54 | pyon | If I defined a function `foo' inside a macro or function `bar', then `foo' can only be used inside `bar', right? |
| 03:54 | pyon | define* |
| 04:02 | pyon | Is there anything like `when-let`, but accepting multiple bindings? |
| 04:03 | pyon | Also, what's the difference between `defn` and `letfn`? |
| 04:03 | pyon | Or, rather, why do we need them both? |
| 04:15 | hiredman | because clojure is not scheme |
| 04:15 | hiredman | def in clojure always creates a top level binding, defn expands to a def + fn |
| 04:16 | hiredman | letfn creates local bindings and the names are all in scope for the functions bound to the names |
| 04:16 | hiredman | (similar to letrec) |
| 04:33 | pyon | hiredman: ah! |
| 05:24 | zajira | i'm new to clojure, how I import http-kit into the lein REPL? I already added http-kit to my project.clj, but I get "No such namespace: http-kit" |
| 05:47 | macro-pyon | What's the convention for embedding code in docstrings? |
| 05:47 | macro-pyon | Markdown? |
| 06:10 | expez | macro-pyon: no real convention, but I've only ever seen people use MD. |
| 06:11 | expez | macro-pyon: It's more about what your tools can handle. CIDER will highlight stuff embedded with `` in docstrings and comments for example. |
| 06:11 | expez | embedded in* |
| 06:12 | expez | Is : a part of the keyword, or is it more correct to think of this as a token for the reader? |
| 06:12 | expez | I'm leaning toward the latter |
| 06:12 | expez | ,(name :foo) |
| 06:12 | clojurebot | "foo" |
| 06:13 | expez | which I think should return ":foo", for the former interpretation to hold |
| 06:14 | expez | I'm asking because we're still highlighting the : with keyword face in clojure-mode, even though the package prefix is now in a different color. I'm starting to think this is a mistake. |
| 06:14 | vijaykiran | ,[(keyword "a")(keyword :a)(keyword "a")] |
| 06:14 | clojurebot | [:a :a :a] |
| 06:17 | justin_smith | ,(keyword ":do not do this") |
| 06:17 | clojurebot | ::do not do this |
| 06:30 | WickedShell | Is the ^:const hint considered valid/used with fn's? |
| 06:30 | justin_smith | you can use it, bu afaik it won't do anything |
| 06:31 | WickedShell | Not surprised to hear that (or really bothered tbh) |
| 07:09 | pyon | Is there a better way to do this? https://www.refheap.com/111232 |
| 07:09 | pyon | I've been wondering if I could use `loop` instead. |
| 07:11 | pyon | Errr, replace diff-loop with differentiate. |
| 07:11 | pyon | https://www.refheap.com/111234 fix'd |
| 07:20 | justin_smith | that seq call is redundant - the destructuring implies it |
| 07:20 | pyon | Ah! |
| 07:21 | justin_smith | otherwise, looks good to me (maybe you could avoid using the same lhs twice in the let binding). |
| 07:22 | justin_smith | ,(let [[h & t] "hello"] [h t]) |
| 07:22 | clojurebot | [\h (\e \l \l \o)] |
| 07:23 | pyon | Ah! |
| 07:23 | pyon | If let bindings are sequential, this should do what I want it to do. |
| 07:23 | pyon | But, yeah, I should probably rename the second `xss`. |
| 07:24 | justin_smith | yes they are sequential |
| 07:29 | pyon | Is there no way to make this code shorter? (fn [[i xs]] [i (cons x xs)]) seems too long for what it achieves. |
| 07:31 | justin_smith | #(update-in % 1 conj x) if xs is a list, and [i xs] is a vector |
| 07:31 | justin_smith | err |
| 07:31 | justin_smith | update, not update-in |
| 07:31 | pyon | Ah! |
| 07:32 | justin_smith | ,(update [:a '(:b :c :d)] 1 conj :aa) |
| 07:32 | clojurebot | [:a (:aa :b :c :d)] |
| 07:32 | justin_smith | it breaks if they are not list and vector though |
| 07:44 | xeqi | pyon: I'd prolly write that as a variation of https://www.refheap.com/111236 |
| 07:44 | pyon | Whoa, that's so much neater. |
| 07:45 | pyon | Alas, incorrect. :-| |
| 07:46 | pyon | Also, constantly performing (take i) and (drop i) for all values of i... is a little tad inefficient, isn't it? :-O |
| 07:46 | xeqi | ack, pasted the wrong one. (drop (inc i) xs) |
| 07:46 | pyon | Ah, good. |
| 07:50 | xeqi | might be. But I could see it the same as conj-ing the list when the (map fun (map fun (map fun xss))) stack unwinds with a layer for each previous value in the original |
| 07:50 | xeqi | if I was performance sensitive, I'd assume xs is a vector and use (subvec ...) |
| 07:51 | pyon | What's subvec do? |
| 07:51 | pyon | Never mind. Me being stupid. :-| |
| 07:51 | pyon | Can vectors be efficiently concatenated, though? |
| 07:59 | xeqi | `concat` returns a lazy seq that walks underneath, so depends on how you're going to use it later. An alternative is `into` (https://www.refheap.com/111237) which uses transients underneath to build a new sequence |
| 08:00 | xeqi | here's where I refer you to setup a suite with https://github.com/hugoduncan/criterium if this seems performance sensitive |
| 08:00 | pyon | Checking. |
| 08:07 | pyon | From [1 2 3 4 5], how do I get [[] [1] [1 2] [1 2 3] [1 2 3 4] [1 2 3 4 5]]? (not necessarily vectors) |
| 08:07 | pyon | And also [[1 2 3 4 5] [2 3 4 5] [3 4 5] [4 5] [5] []]. |
| 08:09 | justin_smith | ,(iterate pop [1 2 3 4 5]) |
| 08:09 | clojurebot | ([1 2 3 4 5] [1 2 3 4] [1 2 3] [1 2] [1] ...) |
| 08:09 | justin_smith | ,(iterate rest [1 2 3 4 5]) |
| 08:09 | clojurebot | ([1 2 3 4 5] (2 3 4 5) (3 4 5) (4 5) (5) ...) |
| 08:10 | justin_smith | you'll want a test for when it ends up empty |
| 08:10 | justin_smith | or a take-while |
| 08:10 | pyon | Ah! |
| 08:10 | justin_smith | ,(take-while seq (iterate rest [1 2 3 4 5])) |
| 08:10 | clojurebot | ([1 2 3 4 5] (2 3 4 5) (3 4 5) (4 5) (5)) |
| 08:10 | justin_smith | ,(take-while seq (iterate pop [1 2 3 4 5])) |
| 08:10 | clojurebot | ([1 2 3 4 5] [1 2 3 4] [1 2 3] [1 2] [1]) |
| 08:11 | justin_smith | when it's not a vector, you can use but-last instead of pop, but pop is much better for vectors |
| 08:11 | pyon | Ah! |
| 08:11 | pyon | ,(let [xs [1 2 3 4 5]] (map vector (range) xs (iterate pop xs) (iterate rest xs))) |
| 08:11 | clojurebot | ([0 1 [1 2 3 4 5] [1 2 3 4 5]] [1 2 [1 2 3 4] (2 3 4 5)] [2 3 [1 2 3] (3 4 5)] [3 4 [1 2] (4 5)] [4 5 [1] (5)]) |
| 08:12 | pyon | Wait, no, I need something like the reverse of (iterate pop xs). |
| 08:13 | justin_smith | well, we do have reverse |
| 08:13 | pyon | yeah, but that turns out to be O(n²). |
| 08:14 | justin_smith | why n squared instead of n? |
| 08:15 | pyon | I mean, for the thing. Each reverse is O(n). |
| 08:15 | pyon | But I need n reverses. |
| 08:17 | justin_smith | ,(reduce conj [] [1 2 3 4 5]) |
| 08:17 | clojurebot | [1 2 3 4 5] |
| 08:17 | justin_smith | err |
| 08:17 | justin_smith | ,(reductions conj [] [1 2 3 4 5]) |
| 08:17 | clojurebot | ([] [1] [1 2] [1 2 3] [1 2 3 4] ...) |
| 08:17 | pyon | Why can I do (#(vector %1 %2 %1 %2) "foo" "bar"), but not (#([ %1 %2 %1 %2]) "foo" "bar") ? |
| 08:17 | pyon | Ah! |
| 08:18 | justin_smith | ,'#([:a]) ; this should help |
| 08:18 | clojurebot | (fn* [] ([:a])) |
| 08:19 | pyon | Ah! |
| 08:25 | pyon | What's the function for getting the i-th element of a vector? |
| 08:25 | justin_smith | nth |
| 08:25 | justin_smith | with a vector you can also use get |
| 08:25 | pyon | Ah, sweet. :-) |
| 08:26 | justin_smith | ,((juxt nth get) [:a :b :c] 1) |
| 08:26 | clojurebot | [:b :b] |
| 08:26 | justin_smith | ,(get-in [:a [:b [:c [:d [:e]]]]] [1 1 1 0]) |
| 08:26 | clojurebot | :d |
| 08:26 | justin_smith | ,(get-in [:a [:b [:c [:d [:e]]]]] [1 1 1 1 0]) |
| 08:26 | clojurebot | :e |
| 08:30 | pyon | I found a neat solution: https://www.refheap.com/111238 :-) |
| 08:31 | pyon | Well, actually, it's mostly based on what you guys suggested. :-) |
| 08:31 | TEttinger | ,([0 1 2 3] 0) |
| 08:31 | clojurebot | 0 |
| 08:31 | TEttinger | ,([0 1 2 3] 3) |
| 08:31 | clojurebot | 3 |
| 08:31 | TEttinger | ,([0 1 2 30] 3) |
| 08:31 | clojurebot | 30 |
| 08:31 | TEttinger | vectors are functions of numerical indices too |
| 08:31 | pyon | :-O |
| 08:32 | pyon | That makes sense. |
| 08:32 | TEttinger | similar to maps and their keys |
| 08:32 | TEttinger | ,({:a 1 :b 2} :b) |
| 08:32 | clojurebot | 2 |
| 09:28 | sobel | but keys are functions and indices are not, so you can write (:a {:a 1 :b 2}) => 1 but (1 [2 3 4]) yields an exception |
| 09:29 | sobel | just to note a little asymmetry there :) |
| 09:49 | pyon | What was the syntax for creating a record value? (not the record type) |
| 09:50 | pyon | Oh, there was a dot at the end of the record's name! I forgot that. |
| 09:57 | Glenjamin | there's also the clojure function ->Record |
| 09:58 | Glenjamin | ,(do (defrecord Example [a b]) [(Example. 1 2) (->Example 1 2) (map->Example {:a 1 :b 2})]) |
| 09:58 | clojurebot | [#sandbox.Example{:a 1, :b 2} #sandbox.Example{:a 1, :b 2} #sandbox.Example{:a 1, :b 2}] |
| 10:10 | pyon | Could someone please help me debug this macro? https://www.refheap.com/111241 |
| 10:10 | pyon | When I run this in the REPL, I get the desired result: `[~@(mapcat (partial constructor-partial-derivative :r) node)] |
| 10:10 | pyon | But, for some reason, when I run it from within the macro, it doesn't work. :-| |
| 10:34 | xeqi | pyon: in total-differential you want `map-indexed` instead of `keep-indexed` since you keep everything |
| 10:34 | pyon | Ah, thanks! |
| 10:34 | pyon | Also, I found the solution to the defderivative problem. |
| 10:34 | pyon | I needed an eval. |
| 10:34 | pyon | (eval base) |
| 10:41 | xeqi | pyon: can defderivative be a function? looks like it just evaluates everything and passes it through? |
| 10:41 | pyon | xeqi: defderivative isn't finished. |
| 10:41 | pyon | In the end, it will be a macro - a much more complex one than defpolynomial. |
| 10:42 | pyon | It's just that I needed to see something for debugging purposes. |
| 11:34 | pyon | Is there anything like map, but which leaves the first element untouched? |
| 13:50 | gfredericks | pyon: that'd be a pretty weird function to have built in I think, but it's easy to write yourself |
| 13:51 | gfredericks | ,(defn map-rest [f coll] (if (empty? coll) coll (cons (first coll) (map f (rest coll))))) |
| 13:51 | clojurebot | #'sandbox/map-rest |
| 13:51 | gfredericks | ,(map-rest inc (range 5)) |
| 13:51 | clojurebot | (0 2 3 4 5) |
| 13:51 | gfredericks | ,(map-rest dec ()) |
| 13:51 | clojurebot | () |
| 13:55 | xeqi | ,(map-rest dec nil) |
| 13:55 | clojurebot | nil |
| 13:56 | xeqi | ah, map returns () cause it uses lazy-seq |
| 13:57 | J_Arcane | ,(first ()) |
| 13:57 | clojurebot | nil |
| 13:57 | J_Arcane | ,(rest ()) |
| 13:57 | clojurebot | () |
| 14:36 | justin_smith | ,(map (juxt rest next) [() [] nil]) |
| 14:36 | clojurebot | ([() nil] [() nil] [() nil]) |
| 14:53 | xeqi | what function turns a vec of keys and a vec of vals into a map? |
| 14:53 | justin_smith | zipmap |
| 14:53 | justin_smith | ,(zipmap [:a :b :c] [1 2 3]) |
| 14:53 | clojurebot | {:a 1, :b 2, :c 3} |
| 14:54 | xeqi | (inc justin_smith) |
| 14:54 | xeqi | oh, right.. no lazybot |
| 15:24 | skoude | Noob question,, but I have a json parsed with chesire.. and it's like [ { employee: {firstname: "test", lastname: "test" }, employer: { companyid: "test"} } , {employee: {firstname: "test2", lastname: "test2}, employer: {companyid: "test2"} }].. So how can I get all of the firstnames? |
| 15:25 | skoude | I tried to use (get-in parsed_json["employee" "firstname"], but it does not work |
| 15:27 | justin_smith | if that's the real structure, it should be (get-in parsed_json [0 "employee" "firstname"]) |
| 15:28 | justin_smith | unless you provided the keywordize option to cheshire, in that case change the strings to keywords |
| 15:28 | rhg135 | or map it |
| 15:28 | justin_smith | oh, all the first names |
| 15:28 | justin_smith | missed that part, right you are rhg135 |
| 15:29 | skoude | thanks, now I got it. I had the keywordize option so I use keywords and it works :) |
| 15:36 | skoude | hmm.. I used (cheshire.core/parse-string s true)) to parse the json.. and if I print the parsed json, it looks okay.. but still I get only nil when using: get-in parsed_json [0 "employee" "firstname"]) |
| 15:36 | justin_smith | skoude: those still are not keywords |
| 15:36 | justin_smith | and the true option specifies it should make kewords |
| 15:36 | skoude | sorry pasted wrong line: ude (+i) 8:fn/#clojure (+cnt) Act: 1,2,3,4,5,6,11,13 |
| 15:37 | justin_smith | (map #(get-in % [:employee :firstname]) parsed_json) |
| 15:37 | skoude | used get-in parsed_json [0 :employee :firstname]) |
| 15:38 | skoude | and still get nil |
| 15:38 | justin_smith | what does it look like when you just enter parsed_json at the repl and see the contents? |
| 15:38 | skoude | it looks perfectly okay :) |
| 15:38 | justin_smith | skoude: can I see it? |
| 15:39 | skoude | justin_smith: I cannot paste it straight because it's a json from production system... But it starts like: |
| 15:40 | skoude | [ |
| 15:40 | skoude | { |
| 15:40 | skoude | "employee": { |
| 15:40 | skoude | "firstname": "KAI", |
| 15:40 | skoude | "lastname": "KALLUNKI", |
| 15:40 | justin_smith | that's not parsed |
| 15:40 | justin_smith | that's json |
| 15:40 | skoude | I use println to print it, and I tough that just a clojures way to display it? |
| 15:41 | justin_smith | no, clojure will not display a real hash-map that way, use prn on it |
| 15:41 | justin_smith | I bet you will discover an unparsed string with prn |
| 15:42 | skoude | yeah prn displays: "[\n {\n \"employee\": {\n \"firstname\": \"KAI\",\n |
| 15:42 | justin_smith | yes, that is an unparsed string |
| 15:43 | skoude | hmm.. strange, because I still call: (def parsed_json( parse json)) |
| 15:44 | justin_smith | is the json somehow double-encoded? |
| 15:44 | skoude | and parse is the function that has: (cheshire.core/parse-string s true)) -defined |
| 15:46 | skoude | aah now I got it.. the problem was this: (def json (pr-str(:body (http-get-request |
| 15:46 | skoude | it should be only: (def json (:body (http-get-request "http |
| 15:48 | skoude | now if I do prn it shows like: ({:employee { |
| 16:03 | skoude | Thanks for the help, it works perfectly now.. Just takes a little time to get used to clojure when coming from java |
| 16:05 | justin_smith | in general, don't trust println to show you what something actually is - use prn for less ambiguity |
| 16:05 | skoude | thanks for the tip, will do and use that |
| 16:06 | justin_smith | ,(println {:a "0 :b 1"}) |
| 16:06 | clojurebot | {:a 0 :b 1}\n |
| 16:06 | justin_smith | ,(prn {:a "0 :b 1"}) |
| 16:06 | clojurebot | {:a "0 :b 1"}\n |
| 16:09 | cloj_dev | whats wrong with this destructuring of a vector? http://pastebin.com/kbvDGxCj |
| 16:24 | Glenjamin | you have two arguments |
| 16:24 | Glenjamin | a map, then a vector |
| 16:24 | Glenjamin | but you're calling it with only a vector |
| 16:25 | ianhedoesit | also your map destructuring is not probably how you expect it to be. |
| 16:26 | ianhedoesit | if you try `(foo {0 :a 3 :b} [1 2 3 4])` you might see part of the problem. |
| 16:26 | ianhedoesit | I might recommend this helpful cheatsheat (https://gist.github.com/john2x/e1dca953548bfdfb9844) to compare - specifically https://gist.github.com/john2x/e1dca953548bfdfb9844#maps in this case. |
| 16:27 | justin_smith | ,(let [{a 0 b 1} [:foo :bar]] [b a]) |
| 16:27 | clojurebot | [:bar :foo] |
| 16:27 | jonathanj | hmm, how do i return a value from :post! in liberator? |
| 16:28 | justin_smith | ianhedoesit: the map syntax works fine for selecting indexes, see above |
| 16:28 | ianhedoesit | justin_smith: huh, interesting. |
| 16:28 | justin_smith | ianhedoesit: because vectors are associative by index |
| 16:28 | ianhedoesit | right, that makes sense. |
| 16:28 | irctc | Hello everyone. |
| 16:28 | justin_smith | it should fail with a list though |
| 16:29 | ianhedoesit | (it does) |
| 16:29 | irctc | I need help setting up reagent. I've been trying to figure it out but I just can't get it to work. Can somebody help me please? |
| 16:29 | ianhedoesit | I'm still going to assume that that wasn't what cloj_dev was trying to do, however. but maybe I'm wrong |
| 16:30 | justin_smith | irctc: do you have specific questions? |
| 16:31 | cloj_dev | lein new reagent |
| 16:31 | irctc | Yes. I put reagent in the dependencies in the project.clj file in my compojure project and Eclipse/counterclockwise plugin downloaded them all automatically for me. Now, how do I actually imlplement reagent in my web pages? |
| 16:32 | irctc | Do I put require [reagent.core :as r] in my views.clj file that renders my webpage and write my reagent code there or should I do something else? |
| 16:33 | justin_smith | irctc: first step is to set up clojurescript. reagent is not clojure (clj) it is clojurescript (cljs) |
| 16:34 | irctc | Ok, so in order for reagent to work I first need to download the dependencies for clojurescript? |
| 16:34 | justin_smith | irctc: next step is to have a cljs file that calls reagent.core/render-component, that sets up the rendering and you need to pass it an atom, changes to that atom will make new re-rendering of the page happen |
| 16:34 | justin_smith | irctc: your dep manager should do that for you, what you need to do is define a clojurescript build in your project |
| 16:34 | justin_smith | irctc: are you using leiningen? |
| 16:35 | irctc | Yes I am. leiningen and compojure for my web app. |
| 16:35 | irctc | And hiccup to render html5 components. |
| 16:35 | justin_smith | OK, so your first step is to check out lein-cljsbuild which you can use to set up clojurescript building |
| 16:36 | justin_smith | irctc: reagent is similar to hiccup (uses the same input syntax just about) but runs on the browser instead of your server |
| 16:37 | justin_smith | irctc: once you can get a basic hello-world cljs built and embedded into your html page and displaying when you load the page, you can move on to pulling in reagent |
| 16:37 | irctc | Ok, so I should set up lein-cljsbuild in my compojure app before I set up reagent? |
| 16:37 | cloj_dev | I'm trying to do something like this in clj http://pastebin.com/8mz7yZBT |
| 16:37 | cloj_dev | I know why its wrong but I can't figure out a good solution |
| 16:38 | justin_smith | irctc: right, reagent is a dep that cljsbuild will use, cljsbuild will make javascript from your clojurescript code, that the browser will run to create your page |
| 16:39 | irctc | Ok, great. Thanks for your guidance. I might have some more questions as I go along setting it up, but I'm gonig to try and set everything up now. |
| 16:39 | justin_smith | lein-cljsbuild and the reagent project both have good docs |
| 16:40 | cloj_dev | reagent is very easy to get going if you have lein |
| 16:40 | ianhedoesit | cloj_dev: are you trying to reverse a vector? |
| 16:40 | cloj_dev | sort of |
| 16:41 | ianhedoesit | or are you trying to stagger it backwards? |
| 16:41 | justin_smith | cloj_dev: that won't ever return - you need a conditional around recur |
| 16:41 | cloj_dev | I want (foo [1 2 3 4]) to be [2 1 4 3] |
| 16:42 | justin_smith | yeah, all you need is an if check for rest being empty, and just returning [b a] if rest is empty |
| 16:42 | justin_smith | well - you might need one or two other things, but that will be a start |
| 16:42 | jonathanj | any recommended HTTP client libraries? |
| 16:43 | jonathanj | i have no idea how to choose between the top few google results |
| 16:43 | justin_smith | jonathanj: I've found http-kit.client better than clj-http.client |
| 16:43 | jonathanj | justin_smith: why? |
| 16:44 | justin_smith | clj-http has some bad behaviors for poorly behaved endpoints in my experience, and wasn't nearly as nice for async stuff |
| 16:44 | justin_smith | for example timeout arguments seemingly not working as expected |
| 16:44 | cloj_dev | hm this function won't work |
| 16:44 | cloj_dev | http://pastebin.com/zhmDfU09 |
| 16:45 | jonathanj | justin_smith: thanks, that sounds like a good recommendation |
| 16:46 | ianhedoesit | cloj_dev: what do you mean it won't work? |
| 16:46 | justin_smith | cloj_dev: do you expect your input to be individual items, or a sequence? |
| 16:46 | cloj_dev | a sequence I beliece |
| 16:46 | ianhedoesit | (foo 1 2 3 4) outputs "fun" |
| 16:46 | cloj_dev | like [1 2 3 4] |
| 16:46 | cloj_dev | oh |
| 16:46 | justin_smith | cloj_dev: because as of now it is looking for individual items, you need an extra pair of [] around the arg list |
| 16:46 | cloj_dev | ah okay |
| 16:46 | cloj_dev | good call |
| 16:47 | justin_smith | because the recursive version would be a pain without that |
| 16:47 | cloj_dev | thanks |
| 16:57 | irctc | I ran into a problem installing lein-cljsbuild. When I try to do lein cljsbuild auto like it says on the github page: https://github.com/emezeske/lein-cljsbuild I get an error. |
| 16:57 | irctc | lein cljsbuild auto Watching for changes before compiling ClojureScript... Exception in thread "main" java.io.FileNotFoundException: Could not locate cljs/util__init.class or cljs/util.clj on classpath: , compiling:(cljs/closure.clj:1:1) |
| 16:58 | irctc | I have no idea what that exception is all about. |
| 16:58 | justin_smith | irctc: can you share your project.clj on refheap? |
| 17:00 | irctc | Sure. Here it is: https://www.refheap.com/78c74e95513c162e1816f5cec |
| 17:02 | justin_smith | my first guess is an incompatibility between your clojurescript dep version and the lein-cljsbuild dep version |
| 17:03 | irctc | I just took the latest ones, like it says on their github pages. |
| 17:03 | cloj_dev_ | hm, this gives an infinite loop http://pastebin.com/Bbk4rS9x |
| 17:04 | justin_smith | irctc: sure, but I don't think they can guarantee they are compatible with every cljs version - and the error you got looks like an incompatible version issue between cljs and cljsbuild |
| 17:05 | justin_smith | cloj_dev_: you are never modifying that "rest" argument - it will never change in that loop |
| 17:05 | justin_smith | so if it starts non-empty, it can never end up empty |
| 17:05 | cloj_dev_ | ah right |
| 17:06 | irctc | Ok, I'm going back to 0.0-3190 Hopefully that works. |
| 17:06 | irctc | I tried 1.7.10 but that just produced the same error. |
| 17:11 | irctc | Ok if it works is it supposed to just say Watching for changes before compiling ClojureScript... and not give me back my prompt? |
| 17:11 | justin_smith | right |
| 17:11 | justin_smith | unless you provide the "once" arg |
| 17:11 | justin_smith | if you provide once it will exit after compiling |
| 17:11 | justin_smith | it will recompile if it sees new cljs files or edits to existing files |
| 17:12 | justin_smith | next step is to pull the generated js into your html so that it can run |
| 17:12 | irctc | Ok. And how do I now run my lein ring server command? Do I just leave this terminal window open and just run it from another one? |
| 17:12 | justin_smith | yeah, just run it in a different terminal |
| 17:13 | justin_smith | stepping away from the computer for a bit... I'll check in later |
| 17:13 | irctc | Oh, ok, so the next step for me is to actually create a clojurescript file and then incorporate it into my views.clj function that will generate my page? |
| 17:13 | irctc | Ok, thanks a lot for all your help. :) |
| 17:13 | jonathanj | justin_smith: how do i send a custom body with http-kit.client? |
| 17:14 | jonathanj | justin_smith: in this case i want to send a JSON body in a POST request |
| 17:14 | jonathanj | i see :form-params but it sounds like it's form-encoded? |
| 17:15 | jonathanj | apparently :body is an option, although the client docs <http://www.http-kit.org/client.html> fail to mention it |
| 17:16 | cloj_dev_ | darn, still getting an infinite loop http://pastebin.com/ZmDbh6T5 |
| 17:21 | ianhedoesit | cloj_dev_: you're still not doing anything with the rest of the list. if you change `[d c]` to `(println [d c])` you'll see what's happening |
| 17:24 | cloj_dev_ | hm tried that |
| 17:24 | cloj_dev_ | it did what I expected I think |
| 17:26 | oddcully | jonathanj: something like e.g. (es/post (str uri url-part) {:content-type :json :as :json :body (json/generate-string request)})) |
| 17:52 | irctc | In clojurescript in my project.clj where it says: :source-paths ["src-cljs"] where is that source path actually supposed to be? |
| 17:52 | irctc | Is it supposed to be on the same level as src or in the resources or in resources/public? |
| 17:52 | irctc | Or somewhere else? |
| 18:05 | justin_smith | irctc: that is the path from the project.clj to the top level of the sources |
| 18:06 | justin_smith | so yeah, same level as src |
| 18:07 | irctc | Thank you. :) |
| 18:08 | irctc | I actually compiled my clojurescript file into a main.js file, but I can't see the newly formed file in my eclipse editor. |
| 18:09 | irctc | Nevermind. I found it in my file system. |
| 18:09 | irctc | For some reason eclipse is just not showing it in the file structure. |
| 18:11 | irctc | So when I have multiple clojurescript files, will they all get compiled into this single main.js file? |
| 18:16 | justin_smith | the main.js file will make the rest of them load, but you don't get the single file without advanced compilation iirc |
| 18:18 | irctc | Ok. |
| 18:18 | irctc | And now when I call the main.js in my views.clj file, how do I point to the actual function that I want to display its results on my page? |
| 18:19 | irctc | I am using this to call the main.js file: (hic-p/include-js "/js/main.js") |
| 18:19 | justin_smith | your html should load your main.js and run some function in it |
| 18:19 | irctc | That doesn't happen. |
| 18:19 | justin_smith | irctc: it has to |
| 18:20 | justin_smith | irctc: there's no magic that makes a browser run clojurescript |
| 18:20 | justin_smith | there has to be a js file, and there has to be some html file that makes the browser load the js file |
| 18:20 | justin_smith | your cljs is just there to be compiled and turned into that js |
| 18:20 | irctc | I put the call to the main.js in my hed generating function which works as it generates all other html elements, but it doesn't render the simple "Hello world text" from my clojurescript file. |
| 18:21 | irctc | Head generating function* |
| 18:21 | justin_smith | OK sure, you can generate the html |
| 18:22 | justin_smith | point is, the entry point is the html which the browser understands, then you set up your rendering to happen when your main method in cljs gets called |
| 18:22 | justin_smith | eventually, that should be a call to reagent |
| 18:22 | justin_smith | once you establish you can get your cljs to load and run |
| 18:23 | irctc | So do I call the cljs function from my views.clj file just like I would with any other function? |
| 18:23 | justin_smith | how would your clj code make anything happen in the browser? |
| 18:24 | justin_smith | I mean it can, but you need some mechanism of communication... |
| 18:26 | irctc | Well this is what I am confused about. I am calling the main.js file and I am assuming that it loads because I loaded a plain javascript file the same way. Next I want it to display the words "Hello world" on my page that the clojurescript function (hello) makes, but when I open my browser window that doesn't write anything on my page. |
| 18:28 | rhg135 | You have to call that function |
| 18:28 | justin_smith | irctc: right, this is the part where reagent comes in. First verify your cljs runs (eg. you can run (.alert js/window "hello") inside your cljs and verify you get the popup), after that to get rendering happening, that is when you start using reagent |
| 18:28 | irctc | If the main.js file makes the rest of the clojurescript files load, then how do I access my hello function in example.cljs and load the results of executing that function on my page? |
| 18:28 | justin_smith | rhg135: well, just because some function returned "hello world" isn't enough to make the browser show the message |
| 18:29 | justin_smith | irctc: you need a client side renderer, that's what reagent does |
| 18:29 | justin_smith | irctc: or you can play with the dom, or with jquery, but right now those would both be wastes of your time |
| 18:29 | irctc | Ok, I'm going to verify that it works first with that alert message. |
| 18:30 | rhg135 | Oh, I misread, justin_smith, right |
| 18:30 | justin_smith | cool, and if that works, you can start hooking up reagent, then things get fun :) |
| 18:30 | irctc | I can't wait. Keeping my fingers crossed. :) |
| 18:32 | irctc | It worked!!! :D |
| 18:33 | irctc | I don't know I've ever been so happy to see an alert message before. lol :D |
| 18:34 | justin_smith | irctc: cool, next step, now that you know you can compile cljs and make it run, is make sure you have reagent in your deps, and call reagent/render-component with the apropriate args |
| 18:34 | justin_smith | irctc: spend some time with the reagent docs, they are really good and thorough, and you should be able to follow along with any examples now that you have this much set up |
| 18:35 | justin_smith | irctc: reagent/render-component will watch an atom, and every time the atom changes, it will update the contents of the page (that's the big picture, of course there are lots of details to set up) |
| 18:36 | irctc | Thanks so much! :) |
| 18:36 | irctc | Btw, when calling reagent/render-component, do I call that in my views.clj file or in the cljs file? |
| 18:37 | justin_smith | in the cljs |
| 18:37 | irctc | And when I require reagent do I need to require it in my views.clj as well or just in my cljs file? |
| 18:37 | justin_smith | since it needs to run in the browser |
| 18:37 | justin_smith | irctc: what does views.clj do? |
| 18:37 | irctc | Generates my pages. |
| 18:37 | irctc | Part of my compojure framework. |
| 18:38 | justin_smith | yeah, this is actually an alternate way to generate pages - because compojure doesn't run in the browser |
| 18:38 | justin_smith | the concept is that instead of making the page on the server and sending to the client, the cljs code constructs the page on the client side, and just asks the server for data - views.clj would be used to make handlers that send data the frontend needs |
| 18:39 | irctc | Ok, so in my cljs file, right after I write my function I'll call (reagent/render-component) and that will watch over all of my atoms, and then I can just compile it and load it the same way I did with this previous alert message? |
| 18:41 | irctc | Ok, cool, because then I can use the client to make some async calls to the server to avoid blocking the user. |
| 18:41 | justin_smith | something like that - add the render-component to the main cljs function, and what the reagent docs will show is how to hook up the atoms to manage the page state |
| 18:41 | irctc | That's the whole reason why I'm using cljs and trying to use reagent in the first place. :) |
| 18:41 | justin_smith | and yeah, make async calls to the server (calling functions in views.clj) that load the data you need to load into the page |
| 18:41 | justin_smith | right |
| 18:42 | irctc | Cool, thanks. :) |
| 18:42 | irctc | I am using this for the reagent tutorial https://reagent-project.github.io/ Hopefully I'll be successful in setting it all up. |
| 18:43 | justin_smith | yup, that's the one |
| 18:44 | justin_smith | irctc: if you scroll down a bit, it shows how to set up the cljs namespace and call render-component |
| 18:46 | irctc | Cool. Thanks. :) |
| 18:50 | irctc | I copied and pasted the entire first example that mentions reagent/render-component except for the name of the namespace just to test it out but I can't get anything to display on my page. |
| 18:51 | justin_smith | OK, I bet you will find compilation errors in your cljsbuild window, or js errors in the browser console |
| 18:52 | irctc | Compiling ClojureScript... Compiling "resources/public/js/main.js" from ["srccljs"]... Successfully compiled "resources/public/js/main.js" in 7.157 seconds. |
| 18:52 | irctc | Everything seems allright. |
| 18:52 | irctc | I even restarted the server. |
| 18:52 | justin_smith | ok, how about the browser js console |
| 18:53 | irctc | You were right. There is something in the browser js console: mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create |
| 18:53 | irctc | Although I don't know what that means. |
| 18:54 | justin_smith | that's not an error though |
| 18:56 | irctc | I know, but that's all I get and I don't know why I'm not getting any output on my page. |
| 18:57 | justin_smith | what do you see when you inspect the page (via right-click) |
| 18:58 | irctc | I see it loads the main.js file: <script src="/js/main.js" type="text/javascript"></script> |
| 18:58 | justin_smith | is there anything in the page body? |
| 18:59 | irctc | Other than that there's nothing else there. |
| 18:59 | justin_smith | irctc: in the r/render-component call, what is the last arg? |
| 19:00 | irctc | (.-body js/document) |
| 19:00 | justin_smith | OK, so you tell reagent to render to the document body, but when you inspect the page there is no body? |
| 19:01 | irctc | Exactly. |
| 19:02 | justin_smith | how about making sure there is a body to the page so that it can render? |
| 19:02 | irctc | Well I mean there is a body, there's jut no content in it. |
| 19:02 | justin_smith | I have to go |
| 19:03 | irctc | Ok, thanks for all your help. |
| 19:03 | irctc | I really appreciate it. |
| 19:03 | irctc | :) |
| 19:30 | pyon | I want to make two macros, `deffoo` and `defbar`. `deffoo` creates a bunch of stuff, and the last thing it creates is a variable foo: (`def ~name { :meta ... :data ... :goes ... :here ... }). What I want `defbar` to do is (0) create a foo, (1) some bar-specific work, (2) insert more metadata into the metadata object. |
| 19:31 | pyon | In a language like Common Lisp, I'd just create the metadata object from `deffoo` and then mutate it from `defbar`. |
| 19:31 | pyon | What would a more idiomatic Clojure solution, without mutability, look like? |
| 19:49 | pyon | Is there any function like `map`, but which discards the result of applying the function to the list's elements? |
| 19:50 | pyon | Basically something like (keep func seq), except (func elem) *always* returns nil. |
| 19:51 | rhg135 | run! |
| 19:52 | rhg135 | in 1.8 of course |
| 19:52 | pyon | rhg135: Oh, nice, thanks! |
| 19:52 | rhg135 | 1.7* |
| 19:52 | pyon | I'm using 1.7.0, which comes with my package manager, and run! works. |
| 19:52 | rhg135 | ok good |
| 20:01 | pyon | How do I check whether a symbol refers to an existing variable. |
| 20:01 | pyon | ? |
| 20:03 | rhg135 | resolve |
| 20:04 | rhg135 | ,(do (resolve 'x2) (resolve '+)) |
| 20:04 | clojurebot | #'clojure.core/+ |
| 20:05 | rhg135 | uhh, the former returns nil |
| 20:05 | justin_smith | ,(resolve 'to-quit-smoking) |
| 20:05 | clojurebot | nil |
| 20:06 | rhg135 | ,(resolve 'to-lose-weight) |
| 20:06 | clojurebot | nil |
| 20:06 | pyon | Ah! |
| 20:06 | justin_smith | haha |
| 20:06 | pyon | lol |
| 20:06 | pyon | rhg135: ty! |
| 20:06 | rhg135 | not in cljs though |
| 20:07 | rhg135 | in cljs you need to intrude on the compiler |
| 20:07 | justin_smith | rhg135: can't you do like (aget js/window "your-ns/your-var") or something like that? |
| 20:08 | rhg135 | that assumes you want to hardcode the ns name. so forget DRY |
| 20:08 | justin_smith | rhg135: aget takes a string as an arg... |
| 20:09 | rhg135 | cljs lacks getting the name at runtime, at least back in 201.r4 |
| 20:09 | pyon | Is there any way to tell the Clojure REPL “forget every single thing I've defined before”, without restarting it? |
| 20:10 | justin_smith | rhg135: it's an array operation, you are treating the object as an array and looking up a key in it |
| 20:10 | rhg135 | ,(run! (partial ns-unmap *ns*) (ns-publics *ns)) |
| 20:10 | clojurebot | #error {\n :cause "Unable to resolve symbol: *ns in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: *ns in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: *ns in this conte... |
| 20:11 | rhg135 | err, something lise that |
| 20:11 | justin_smith | run takes a function and a collection |
| 20:11 | justin_smith | err, run! does I mean |
| 20:12 | pyon | :-O |
| 20:13 | rhg135 | justin_smith: I mean you can't know the actual ns name at runtime without hardcoding at compile time. unless dnolen endowed it by now |
| 20:14 | Bronsa | justin_smith: that won't work with advanced compilation |
| 20:14 | justin_smith | Bronsa: ahh, good point |
| 20:14 | Bronsa | I don't think there's a good way to do resolve in cljs |
| 20:14 | justin_smith | rhg135: the ns at runtime is 'user anyway, aside from dev time shenanigans |
| 20:14 | rhg135 | oh and that. thx Bronsa |
| 20:15 | rhg135 | 'cljs.user but yeah |
| 20:16 | rhg135 | you can do it at compile time via the api |
| 20:16 | rhg135 | I think |
| 20:32 | pyon | How could I make a macro for asserting multiple things in a single place? |
| 20:32 | pyon | (multi-assert test1 "failed test1" test2 "failed test2" ...) |
| 20:51 | rhg135 | ,(defmacro multi-assert [& pairs] `(do ~@(for [[t msg] (partition 2 pairs)] `(assert ~t ~msg)))) |
| 20:52 | clojurebot | #'sandbox/multi-assert |
| 20:52 | justin_smith | why would this need to be a macro? |
| 20:52 | rhg135 | ah. yeah he's right |
| 20:54 | justin_smith | well, because assert is a macro I guess... |
| 20:54 | rhg135 | maybe lazyness, aka if a certain test is very expensive |
| 20:54 | justin_smith | though we can still do this without another macro |
| 20:55 | justin_smith | ,(map #(assert (first %) (second %)) [[true "ok"] [false "oops"]]) |
| 20:55 | clojurebot | #<AssertionError java.lang.AssertionError: Assert failed: oops\n(first p1__68#)> |
| 21:32 | pyon | rhg135: justin_smith: ah, thanks! |
| 21:36 | pyon | https://www.refheap.com/111249 -- here, in constructor-metadata, how do I quote the name? |
| 21:37 | pyon | If I do 'name , it gives me (quote name), but what I actually want to quote is the *value* of the variable name. |
| 21:38 | pyon | To be clearer - how do I quote the value of a variable? |
| 21:38 | justin_smith | either the caller needs to quote name, or constructor-metadata needs to be a macro |
| 21:39 | justin_smith | you can't get the quoted version of an argument in a function |
| 21:39 | pyon | Oh. |
| 21:39 | pyon | But, if I make it a macro, then I can't map over it in defpolynomial. Mmm... |
| 21:40 | justin_smith | sounds like the caller needs to quote the names |
| 21:41 | pyon | I can think of ways to do it, but not in syntactically pleasing ways. :-| |
| 21:47 | cloj_dev | I'm still working on this problem : http://pastebin.com/9mBXSgxm |
| 21:47 | cloj_dev | anyone have a suggestion? |
| 21:48 | justin_smith | cloj_dev: next never changes |
| 21:48 | cloj_dev | huh |
| 21:49 | cloj_dev | ah I see that now |
| 21:49 | justin_smith | ,((fn [[a b & rest]] (if (empty? rest) [b a] (concat [b a] (recur rest)))) [1 2 3 4 5 6]) |
| 21:49 | clojurebot | #error {\n :cause "Can only recur from tail position"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.UnsupportedOperationException: Can only recur from tail position, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6891]}\n {:type java.lang.UnsupportedOperationException\n :message "Can only recur from tail position"\n ... |
| 21:49 | justin_smith | hrmph |
| 21:50 | justin_smith | ,((fn flipper [[a b & rest]] (if (empty? rest) [b a] (concat [b a] (flipper rest)))) [1 2 3 4 5 6]) |
| 21:50 | clojurebot | (2 1 4 3 6 ...) |
| 21:50 | justin_smith | it's still bad if the arg count is odd though |
| 21:50 | cloj_dev | oh nice |
| 21:51 | cloj_dev | I thought you can't have recursive functions that don't call recur |
| 21:51 | justin_smith | you can, they just don't get optimized |
| 21:51 | justin_smith | but with laziness (concat) that is less of an issue |
| 21:51 | cloj_dev | oh |
| 21:54 | justin_smith | cloj_dev: it's normal for lazy functions to use direct self-call instead of recur |
| 21:54 | cloj_dev | interesting |
| 21:54 | cloj_dev | how do you know if a function is lazy? |
| 21:54 | cloj_dev | is it self evident, or documented? |
| 21:54 | cloj_dev | or you just know by rote? |
| 21:54 | justin_smith | there's basically one lazy class: clojure.lang.LazySeq |
| 21:55 | justin_smith | lazy functions are the ones that use that class directly (via the lazy-seq function) or call others that use it (like map or concat or filter) |
| 21:55 | justin_smith | functions should document if they are lazy |
| 21:55 | cloj_dev | right cool |
| 21:56 | rarebreed | there's also the delay macro |
| 21:56 | justin_smith | that's not lazy |
| 21:56 | rarebreed | which will delay evaluation of a function |
| 21:57 | justin_smith | yes, but it's not considered lazy by clojure's standards - with a lazy seq accessing the value can force execution, with delay you need to deref |
| 21:57 | justin_smith | I'd group delay closer to future and promise |
| 21:57 | justin_smith | in terms of spheres of functionality |
| 21:58 | rarebreed | yes, if you use delay, you have to force on the result or deref it |
| 21:58 | justin_smith | things that could give you a value, but you may need to wait, and you can check exlicitly whether they are realized |
| 22:01 | pyon | Ok, just to be sure. What's the simplest way to make a macro quoteall, such that (quoteall foo bar qux) expands to ['foo 'bar 'qux] ? |
| 22:05 | pyon | ,(defmacro unusable [foo] (class foo)) (unusable 'foo) ; why? |
| 22:05 | clojurebot | #'sandbox/unusable |
| 22:06 | pyon | ,(unusable 'foo) ; why? |
| 22:06 | clojurebot | clojure.lang.Cons |
| 22:06 | pyon | How is this a cons cell? |
| 22:12 | justin_smith | ,''foo |
| 22:12 | clojurebot | (quote foo) |
| 22:12 | justin_smith | that's why |
| 22:13 | gfredericks | ,(defmacro quoteall [& args] (mapv #(list 'quote %) args)) |
| 22:13 | clojurebot | #'sandbox/quoteall |
| 22:13 | gfredericks | ,(quoteall foo bar qux) |
| 22:13 | clojurebot | [foo bar qux] |
| 22:13 | justin_smith | ~macros |
| 22:13 | clojurebot | macros are just a game with symbols |
| 22:13 | gfredericks | ,(defmacro quoteall [& args] `'[~@args]) |
| 22:13 | clojurebot | #'sandbox/quoteall |
| 22:13 | gfredericks | ,(quoteall foo bar qux) |
| 22:13 | clojurebot | [foo bar qux] |
| 22:13 | gfredericks | haha I just wrote `'[~@args] #yolo |
| 22:14 | pyon | justin_smith: Ah! |
| 22:14 | justin_smith | gfredericks: you could have gotten a #reader-macro in there if you tried |
| 22:15 | justin_smith | and #yolo doesn't count :P |
| 22:15 | pyon | ,(class (first (quoteall (foo bar qux))) |
| 22:15 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 22:15 | pyon | oops |
| 22:15 | pyon | ,(class (first (quoteall (foo bar qux)))) |
| 22:15 | clojurebot | #error {\n :cause "Unable to resolve symbol: quoteall in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: quoteall in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: quoteal... |
| 22:15 | pyon | I'm dumb. |
| 22:15 | pyon | ,(class (first (quoteall foo bar qux)) |
| 22:15 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 22:15 | pyon | Never mind. |
| 22:16 | gfredericks | ,(class (first (quoteall foo bar qux))) |
| 22:16 | clojurebot | #error {\n :cause "Unable to resolve symbol: quoteall in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: quoteall in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: quoteal... |
| 22:16 | gfredericks | ,(defmacro quoteall [& args] `'[~@args]) |
| 22:16 | clojurebot | #'sandbox/quoteall |
| 22:16 | gfredericks | ,(class (first (quoteall foo bar qux))) |
| 22:16 | clojurebot | clojure.lang.Symbol |
| 22:16 | pyon | Ah! |
| 22:16 | pyon | What exactly does `' do? |
| 22:16 | gfredericks | clojurebot is forgetful |
| 22:17 | pyon | Heh, makes sense. :-) |
| 22:17 | justin_smith | pyon: it wraps quote in syntax-quote, and it is usually a sign of mischeaf |
| 22:17 | gfredericks | ,(defmacro quoteall [& args] (list 'quote (vec args))) |
| 22:17 | clojurebot | #'sandbox/quoteall |
| 22:17 | gfredericks | ,(quoteall foo bar qux) |
| 22:17 | clojurebot | [foo bar qux] |
| 22:17 | gfredericks | pyon: ^ that oughta be a much simpler definition to understand |
| 22:17 | pyon | Ah :-) |
| 22:21 | amalloy | ,'`'[~@args] |
| 22:21 | clojurebot | (clojure.core/seq (clojure.core/concat (clojure.core/list (quote quote)) (clojure.core/list (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat args)))))) |
| 22:21 | amalloy | ^ that oughta be a less simple explanation to understand |
| 22:21 | justin_smith | lol |
| 22:23 | OrbitalKitten | hi guys, do you know if there's a way to generate the members in deftype/defrecord without going into eval hell? |
| 22:23 | gfredericks | ,(inc amalloy) |
| 22:23 | clojurebot | #error {\n :cause "Unable to resolve symbol: amalloy in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: amalloy in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: amalloy i... |
| 22:23 | gfredericks | (inc amalloy) |
| 22:23 | gfredericks | OrbitalKitten: I think defrecord has a way |
| 22:24 | gfredericks | ,(defrecord OrbitalKitty [weight velocity]) |
| 22:24 | clojurebot | sandbox.OrbitalKitty |
| 22:24 | gfredericks | ,(OrbitalKitty/getBasis) |
| 22:24 | clojurebot | [weight velocity] |
| 22:24 | OrbitalKitten | ooh by member I mean implementations of the methods |
| 22:24 | gfredericks | ooooh you want to generate implementations of protocol programmatically |
| 22:24 | OrbitalKitten | yeah |
| 22:24 | gfredericks | ,(doc extend) |
| 22:24 | clojurebot | "([atype & proto+mmaps]); Implementations of protocol methods can be provided using the extend construct: (extend AType AProtocol {:foo an-existing-fn :bar (fn [a b] ...) :baz (fn ([a]...) ([a b] ...)...)} BProtocol {...} ...) extend takes a type/class (or interface, see below), and one or more protocol + method map pairs. It will extend the polymorphism of the protocol's methods to call the suppl... |
| 22:25 | gfredericks | it's surprisingly easy :) |
| 22:25 | OrbitalKitten | thanks, I will look at this |
| 22:30 | OrbitalKitten | hmm looks like it only works with Protocols, and i'm implementing a huge ass interface |
| 22:30 | OrbitalKitten | basically it's a visitor that has a ton of visit/endVisit methods |
| 22:31 | OrbitalKitten | I'm using reflection to find out what I need to implement and generate the corresponding methods |
| 22:31 | OrbitalKitten | heh I'll stick with the evil code for now |
| 23:12 | pyon | Does Clojure have anything like Common Lisp's keyword arguments? |
| 23:33 | TEttinger | pyon: I don't know CL, but we do have keyword destructuring for maps as args. I think it's frowned upon |
| 23:34 | TEttinger | ~kwargs |
| 23:34 | clojurebot | kwargs are a bad idea. |
| 23:34 | TEttinger | ~kwargs |
| 23:34 | clojurebot | kwargs are a bad idea. |
| 23:34 | TEttinger | hm |
| 23:34 | pyon | Ah! |
| 23:34 | TEttinger | there's another one |
| 23:34 | TEttinger | it doesn't play well with other clojure stuff though |
| 23:34 | TEttinger | since you can't make a partial fn of it, for instance |
| 23:35 | pyon | Makes sense. |
| 23:35 | TEttinger | it technically takes a single arg, a map that may contain lots of keywords and values, so partial would need a whole new map |
| 23:37 | pyon | Can I understand a macro as a normal function, except its arguments are passed all quoted? |
| 23:39 | amalloy | pyon: yes, except that also its result is expanded into the function calling it, rather than being returned as a value |
| 23:39 | pyon | Ah! |
| 23:40 | pyon | So, in principle, I would write everything in terms of normal functions, and use a single macro `macroize`, that lets me use other existing functions as macros, right? |
| 23:40 | pyon | s/would/could/ |
| 23:41 | TEttinger | usually you should prefer fns because macros can't be passed around as first-class values |
| 23:41 | TEttinger | ,(reduce and [true true true]) |
| 23:41 | pyon | Yeah. I've been running into that a lot. |
| 23:41 | clojurebot | #error {\n :cause "Can't take value of a macro: #'clojure.core/and"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/and, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "Can't take value of a macro: #'clojure.... |
| 23:50 | pyon | So, I could use (defmacro macroize [function & arguments] `(~function ~@(map #(list 'quote %1) arguments))), and define all other macros in terms of normal functions and macroize, right? |
| 23:50 | pyon | Or, is this a bad idea for some reason? |
| 23:51 | amalloy | it's not clear how you intend macroize to work but i'm fairly sure it won't work that way |
| 23:58 | pyon | Can I “delay a ~”? |
| 23:58 | pyon | I'm trying to write a macro that produces a macro. |
| 23:59 | spradnyesh | can someone please explain this? |
| 23:59 | spradnyesh | (= (double 1.0) (float 1.0)) => *true* |
| 23:59 | spradnyesh | and (= (cast java.lang.Double 1.0) (cast java.lang.Float (float 1.0))) => *true* |
| 23:59 | spradnyesh | but (= (:close (second data)) (:close (second rslt))) => *false*, where |
| 23:59 | spradnyesh | (:close (second data)) => 95.2 |
| 23:59 | spradnyesh | (:close (second rslt)) => 95.2 |
| 23:59 | spradnyesh | (type (:close (second rslt))) => java.lang.Float |
| 23:59 | spradnyesh | (type (:close (second data))) => java.lang.Double |