#clojure log - Aug 17 2014

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

0:16 ben_vulpes: what are good patterns for handling changing datomic schemas during deploy? apply the schema when the app boots?

6:51 Rapp: hi everybody

6:51 i am trying to set up my emacs with cider and cider-nrepl

6:52 i installed cider via the emacs 24 package manager.

6:52 and i added cider-nrepl 0.7.0 to my project.clj as described in the docs

6:52 however, i get an error when running cider-jack-in, because cider is 0.8.0 and the cider-nrepl is 0.7.0

6:53 when i switch to 0.8.0-SNAPSHOT for cider-nrepl, i get tons of other errors

6:53 i wonder if it is possible to get the 0.7.0 cider instead...?

6:55 martinklepsch: Rapp: probably better ask that in #emacs

6:56 Rapp: I use cider 0.8.0-alpha & cider-nrepl 0.7.0 and it works fine

6:57 Rapp: martinklepsch: probably. however, i just found out that i am using melpa, not melpa-stable. probably a good idea to switch to the latter ;)

6:57 martinklepsch: don't you get the error that undef is unsupported? maybe that doesn't matter..

6:58 martinklepsch: Rapp: when trying to undef something or when running cider-jack-in

7:28 karls: Rapp: did you solve the problem?

7:28 i had the same problem this morning

7:29 s/same/similar/

7:37 spradnyesh: @Rapp i added "[cider/cider-nrepl "0.8.0-SNAPSHOT"]" to my ~/.lein/profiles.clj and d'loaded "cider" again from melpa. things are working fine now

7:41 karls: spradnyesh, Rapp, exactly that. stick it in the :plugins section, in ~/.lein/profiles.clj

8:20 shafire: do you know a good profiler for clojure?

8:20 need to find some performance bugs

9:16 Pupnik__: shafire, same ones as java/jvm

10:18 sojacques: Hi everyone

10:19 I've been reading more than a few stackoverflow answers, and I still have some trouble with something related to jdbc

10:19 does anyone know how to process results from a sql query before the connection closes?

10:20 Most answers I say mentioned "with-connection" which is deprecated

10:20 saw*

10:21 (the only reason why I need this is for dealing with postgresql arrays, which need an open database connection to be transformed into arrays that I can use)

10:21 Any help would be sincerely appreciated :(

10:23 ggherdov: hi. In my project.clj I list clj-http as a dependancy; when I launch "lein repl", I end up in an error: http://bpaste.net/show/2l1YYL3ZMtFPRtoNht39/ "Could not find or load main class clojure.main"

10:23 if I launch "lein repl" w/o the project.clj file, it goes fine (I mean: I think I have clojure installed correctly). Hints?

10:24 llasram: ggherdov: What version of Leiningen do you have, and how did you install it?

10:25 ggherdov: llasram: checking. Most likely I did it via apt-get (on ubuntu)

10:26 llasram: ggherdov: Oh, actually -- I think the problem is that you don't include a dependency on clojure itself in your project

10:27 ggherdov: llasram: ah, that could be a problem :)

10:27 llasram: ggherdov: That said, you're probably running a 1.x Leiningen

10:27 ggherdov: btw, leiningen 1.7.1

10:28 llasram: Yah. Unless you have some reason you need to work with your distro's packaged version, I'd recommend installing the most recent 2.x release as a "self install": http://leiningen.org/

10:29 ggherdov: llasram: ok, will check that. BTW, copypasting from some code a friend wrote, see [org.clojure/clojure "1.6.0"] among the dependancies. Is it still a reasonable version? I always wander how are you supposed to figure out those version numbers

10:29 llasram: Yeah, 1.6 is the lasted stable release of Clojure

10:29 ggherdov: ok thanks

10:30 llasram: Once you have upgraded to Leiningen 2.x, the lein-ancient plugin can tell you :-)

10:30 https://github.com/xsc/lein-ancient

10:31 ggherdov: awesome! that's a pretty good reason to get 2.x ;)

10:32 thesaskwatch: hi, what is the best and current resource to start learning clojurescript?

11:00 sztamas: Tetris in ClojureScript http://tamas-szabo.com/tetris/

11:00 https://github.com/sztamas/tetris

11:00 :)

11:38 oskarkv: What if I want to get the remainder when dividing x by y, as fast as possible for longs. There is `unchecked-remainder-int`, but what about longs?

11:40 johnwalker: is it possible to have multiple typehints ?

11:41 llasram: johnwalker: In what sense?

11:41 johnwalker: like (defn foo [^Integer ^String x]) ?

11:41 llasram: johnwalker: I'm not sure what that would mean

11:41 johnwalker: x can be either String or Integer

11:42 llasram: Well, mechanically, no -- the type hint is implemented as :tag metadata on the symbol, for which there can be only a single value

11:42 johnwalker: ahh, thats a problem

11:42 llasram: And semantically, -- it wouldn't be meaningful. The hints exist as a hint to the compiler to avoid reflection

11:43 If it could be multiple types, you still need reflection

11:43 justin_smith: sojacques: I work on a codebase that uses jdbc a lot, what's up?

11:43 johnwalker: hehe

11:43 (inc llasram)

11:43 lazybot: ⇒ 34

11:43 johnwalker: thanks

11:44 oskarkv: johnwalker maybe you want to use preconditions, if you just want to assert that what you get is either string or integer

11:45 johnwalker: oskarkv: well, i'm actually cleaning up the jclouds bindings for clojure

11:45 not so much asserts as "wow, including jclouds gives you two pages of reflections warnings"

11:46 oskarkv: hehe

11:46 justin_smith: sojacques: as long as you force all laziness inside jdbc/query, all code inside the jdbc/query block has the open connection to work with

11:47 sojacques: the one gotcha is if you accidentally use for or map inside the with-query block, without forcing the laziness - you will get an error when the lazy items are first forced

12:16 sojacques: justin_smith: Just tried a couple things, and I think I don't fully understand, how would I force laziness using :result-set-fn?

12:16 justin_smith: thanks a lot for answering btw :)

12:18 justin_smith: sojacques: you would ensure that you don't call anything that is lazy

12:19 or if you do call something lazy, you would use doall, dorun, doseq or the like on the lazy sequence to force it

12:19 or reduce over it, or use mapv instead of map...

12:19 sojacques: oh I force the evaluation

12:19 justin_smith: right

12:19 sojacques: damn that's smart

12:20 justin_smith: it's just how we prevent bugs with short lived resources and lazy-sequences - it's not smart, it's just learned via lots of pain and weird bugs :)

12:20 sojacques: thx, will try that

12:20 :)

12:21 justin_smith: one way to look at it, is that laziness assumes a certain amount of purity, and a resource that is limited in time is not pure - so we need to make sure laziness is not created in that impure context

12:31 sojacques: justin_smith: it works, thx

12:31 mori: I have trouble supplying an int array to a Java object with the following function: public void set(double value, int... indices)

12:33 I use .set this v (int-array indices) yet the method signature can't be found

12:53 andyf: johnwalker: If the functions where you have determined an arg can have one of two different types have branches inside of them that depend upon that type, you can type-hint the value either in the interop call, or in a let statement you add yourself specifically for the purpose of attaching a type hint.

12:55 justin_smith: sojacques: sometimes I think we should have a convention where lazy functions are prefixed with ¡ like ¡map ¡for ¡filter etc., to match the ! convention for side effect / unsafe in transaction functions

12:59 sojacques: having something like this would have been a great hint. I don't know how I didn't think about the sequence being lazily evaluated!

12:59 justin_smith: sadly, ¡ is too hard for most people to type

13:00 andyf: In the future it might be possible for a lint tool like Eastwood to catch some such mistakes.

13:00 That doesn't help anyone now, unfortunately.

13:01 justin_smith: andyf: yeah, perhaps by noting constructs that represent a temporary resource, and then alerting about any lazy sequence that accesses that resource

13:02 andyf: It already has built into it a table of which clojure.core functions/macros are lazy. I was thinking just a combination of binding with a function that returns a lazy value in return position inside of binding. But it could be experimented with to see what works well

13:10 justin_smith: ToBeReplaced: you see this? https://gist.github.com/yogthos/911e6aba9802ceacd83c

13:11 ToBeReplaced: linked from this blog post http://yogthos.net/#/blog/56

13:13 ToBeReplaced: justin_smith: yogthos: i see it now; what are the thoughts?

13:14 justin_smith: ToBeReplaced: I just noticed it was working with the same API noi.file does, maybe there is a good idea there we could steal. Though maybe we don't need that, and we just want the wrapper to stay thin.

13:16 ToBeReplaced: justin_smith: yeah... i mean, in our wrapper it's (with-open [watcher (watch-service)] (apply register! path watcher opts) (watch-loop watcher opts))

13:16 so quite a bit tighter... only extra code is the watch-loop, but that's implementation specific

13:16 application specific*

13:17 justin_smith: right

13:18 ToBeReplaced: i think i put a note in there about creating some kind of watcher to push events onto a core.async channel -- i think that's the natural next step

13:18 but that would have to be done in an extension library since it's out of scope

13:18 justin_smith: OK, checking out the latest state of the code now

13:19 ToBeReplaced: as a separate lib, or in an optional namespace?

13:19 ToBeReplaced: separate library, since it would depend on core.async

13:21 if i needed a watch service right now, that's what i'd be writing... something for (with-open [watcher (watch-service)] (let [ch (watch-channel watcher path :entry-modify :entry-create)] (go-loop ...)))

13:23 justin_smith: cool, makes sense

13:24 ggherdov: what is a "clojure.lang.PersistentArrayMap" ? I'm trying to handle it as an hash map to get the value for a given key, but (:foo {"foo" "bar"}) gives me nil instead of "bar"

13:25 ToBeReplaced: ggherdov: your key is "foo" not :foo in the map you provided... (get {"foo" "bar"} "foo") will work

13:25 justin_smith: ,(= "foo" :foo) ; ggherdov

13:25 clojurebot: false

13:26 ggherdov: thanks ToBeReplaced justin_smith

13:26 justin_smith: ggherdov: a PersistentArrayMap is for smaller hashmaps, it gets promoted to PersistentHashMap at bigger sizes

13:26 ggherdov: ok

13:27 justin_smith: ,(map type [(zipmap (range 3) (range 3)) (zipmap (range 100) (range 100))])

13:27 clojurebot: (clojure.lang.PersistentArrayMap clojure.lang.PersistentHashMap)

13:27 ggherdov: i see

13:30 justin_smith: ToBeReplaced: I did some refactoring on the unit tests, and am continuing to work on test coverage (which is my preferred MO for figuring out someone else's code base) - I'll likely run into a wrapper to implement as I work on the tests, and be in touch about any of that.

13:32 antonfr: Is there any way to define clojure variable from java?

13:33 justin_smith: antonfr: via the clojure.lang.RT class, iirc

13:35 oh, with 1.6 there is also clojure.java.api which is better

13:35 ToBeReplaced: justin_smith: cool! that would be great

13:35 justin_smith: https://github.com/clojure/clojure/blob/master/changes.md "Fn plus = Clojure.var("clojure.core", "+");"

13:36 ToBeReplaced: i'm pretty much out of time to work on it for now, as it hits all of my immediate needs, but i'm happy to review and the like

13:36 justin_smith: that's for accessing a var - but I think you could access "def" in order to invok it etc.

13:36 antonfr: through clojure.java.api you can only get and invoke functions

13:36 in which namespace can I find def? I think there is no such macro/function in clojure.core

13:36 justin_smith: antonfr: not macros? so you can't invoke "def" ?

13:37 antonfr: probably macros too, didn't try

13:37 justin_smith: ahh, def must be a special form actually

13:37 you can use intern though

13:37 johnwalker: thanks andyf

13:37 justin_smith: ,#'intern

13:37 clojurebot: #'clojure.core/intern

13:38 justin_smith: ,(doc intern)

13:38 clojurebot: "([ns name] [ns name val]); Finds or creates a var named by the symbol name in the namespace ns (which can be a symbol or a namespace), setting its root binding to val if supplied. The namespace must exist. The var will adopt any metadata from the name symbol. Returns the var."

13:38 justin_smith: that should do what you want

13:38 antonfr: justin_smith: just tried RT.var("user", "self", "foobar"), it works, thank you!

13:38 justin_smith: antonfr: oh, nice

13:39 so clojure.lang.RT was enough then

13:41 antonfr: for other options, I see that the source for intern calls out to interop on clojure.lang.Var/intern

14:00 bbloom_: akhudek: did you ever take a look at https://github.com/kovasb/combinator ?

14:01 akhudek: bbloom_: no, I haven’t. I’ll take a closer look when I get a moment though. Looks interesting!

14:01 bbloom_: akhudek: kovas makes some perf comparisons to fast-zip

14:01 i'm potentially in need of fast-zip, so i was wondering if maybe it could be faster :-)

14:01 akhudek: bbloom_: oh, I think I did see that comparison actually

14:04 sveri: Hi, I am wondering if it is ok to use defprotocol and defrecord similar to using interfaces in java, so that I define my public/internal API with a protocol and implement it with a record that I can create and pass around, or if this is not idiomatic, maybe something else should be used?

14:06 akhudek: bbloom_: I don’t know off hand any way to make fast-zip faster. At one point I tried an implementation based on protocols, but it didn’t seem to help. Some of the items listed by the combinator.zip author could prove useful though.

14:32 justin_smith: sveri: yeah, protocol for definition and record for implementation makes sense. But where it really shines is for making your code more modular, allowing a client of your lib to pass in some object that follows the protocol in order to extend your functionality from the outside.

14:33 which is also similar to java

14:36 gfredericks: if technomancy were here he would ask why you can't use multimethods for that

14:36 justin_smith: heh, sure, if you are concerned that your program may be too fast

14:37 gfredericks: then he would say that if you care about speed over sane semantics then why are you using clojure

14:38 justin_smith: I think we can classify languages in terms of the ordering of Intuitiveness Correctness and Speed -- clojure is csi, python is ics, c is sic

14:38 gfredericks: he would also conjecture that programmers these days are choosing protocols long before they have any idea if it's really a performance issue

14:38 justin_smith: gfredericks: sounds like you know this guy pretty well

14:39 gfredericks: he would say yes, gfredericks is the best simulator of me that I know

14:40 justin_smith: (proxy technomancy [] gfredericks)

14:40 gfredericks: then he would post a link to a clever gif suspiciously quickly

14:41 it would somehow relate to both the simpsons and clojure.core/proxy

14:49 llasram: I do feel like there's a cadre of programmers who reach for protocols too quickly, but when I see that happen, I don't usually think "the fundamental design is sound, but I wish they'd used a multimethod"

14:50 justin_smith: (inc llasram)

14:50 lazybot: ⇒ 35

14:54 justin_smith: frankly, I use both protocols and multimethods very rarely myself

14:54 though I am much more likely to be passing an argument to some function that takes advantage of a protocol or interface the function uses, than a multimethod

14:55 bbloom_: really depends on the sort of code you're writing

14:55 justin_smith: oh, absolutely

14:55 bbloom_: i find that application code very rarely uses custom polymorphism, or if it does, there's like 1 or 2 cases, such that an 'if suffices

14:55 but for library code, i find i almost instantly need polymorphism every time

14:56 justin_smith: I'd say the big exception is if you are already using functions that leverage polymorphism - you can just dogpile on that

14:57 bbloom_: yeah, basically you need polymorphism at the bottom

14:57 if you're building on top, you usually can just get polymorphic behavior for free from polymorphic primitives

14:58 justin_smith: are there good examples of multimethods in clojure.core itself?

14:58 kristof: justin_smith: "heh, sure, if you are concerned that your program may be too fast" chortled pretty hard at that

14:58 bbloom_: justin_smith: only really print-method

14:59 justin_smith: but it's worth remembering that core is on *everyone's* hot path

14:59 Janiczek: Hi, where does CLJS analyzer differentiate between 1, 1N, 1M, 1/2, 1.2 etc? Is it one of the passes? Couldn't find it...

14:59 bbloom_: so it does lots of things you wouldn't otherwise do unless you were optimizing

14:59 justin_smith: right

15:12 sveri: justin_smith: gfredericks Well, I dont choose them because of performance characteristics, I just found them to fit so nicely together with stuarts component library, creating a record and passing that around seems rly easy

15:13 justin_smith: sveri: ahh, so you inherit the need to use a protocol from your underlying lib

15:13 also, that reminds me, I was experimenting with component, need to play with it some more

15:14 sveri: justin_smith: no, I dont inherit, I just define a record and pass that to other components with the state that these records need (mostly db connection and scheduler in my case=

15:14 justin_smith: I meant "inherit" figuratively

15:14 sveri: and as a neat side effect I get an overview of the public api I have inside my application

15:15 justin_smith: in the sense that to use component you need to implement the component/Lifecycle protocol

15:15 ahh, OK

15:15 gfredericks: sveri: I use them for exactly the same purpose :)

15:15 * gfredericks was just playing technomancy's advocate

15:16 sveri: gfredericks: :D ok, sounds good

15:16 gfredericks: justin_smith: it's not really a need; you can use defrecord with component and still use multimethods for your custom interfaces

15:17 justin_smith: OK - but you still need to implement the Lifecycle protocol somewhere, that's all I meant

15:33 gfredericks: ah yeah

15:50 writing a variant of reify for multimethods that use the clojure.core/type dispatch function is gnarly

15:50 fortunately I have no need to do that so I can just give up

15:53 llasram: I've actually thought about it before, and it didn't seem like it would be *too* bad. Just gensym up a keyword to serve as the :type metadata

16:15 blaenk: anyone here use an embedded nrepl?

16:15 I'm trying to figure out if I can get lein or something to recognize the port I'm using and put it in the .nrepl-port file

16:16 llasram: blaenk: You're providing an nREPL server yourself from your application?

16:16 blaenk: yeah

16:17 llasram: blaenk: Then if there's something sensible you can do with setting a project's .nrepl-port, it's up to you to do that

16:17 blaenk: I'm sorry can you rephrase that

16:17 llasram: Leiningen knows what to put in the .nrepl-port file because it just writes the port it uses when it launches a REPL

16:17 blaenk: got it

16:18 llasram: If you want .nrepl-port to contain the port of your nREPL server, you need to write it there

16:18 blaenk: yeah I was wondering if leiningen perhaps had a setting I could set to my own custom nrepl port

16:18 and if not then yeah I guess writing it myself is the only way

16:18 but I hesitated to do that because I didn't know if lein would then overwrite it anyways

16:19 llasram: Oh, it will the next time it launches an nREPL server, but that's exactly what happens if you try to launch multiple simultaneous REPLs via lein for the same project anyway

16:19 blaenk: ohh okay

19:42 lavokad: aksdjasaksdjas

19:51 AeroNotix: agreed

20:24 lavokad: Hi, I'm strugling to understand about some concept related with macros. Post I've read say that Lisp macros aren't viable, possible in Java because of java doesn't provide the developers with the access, neither the syntax to its ASTs. That the way to implement a macro in Java would requiere to pass it ASTs as arguments, and return the desired code transformation as an AST. What I don't understand is why inside the implementation of the '

20:32 kristof: lavokad: your message was truncated.

20:33 gfredericks: at "implementation of the '"

20:35 lavokad: Hi, I'm strugling to understand about some concept related with macros. Post I've read say that Lisp macros aren't viable, possible in Java because of java doesn't provide the developers with the access, neither the syntax to its ASTs. That the way to implement a macro in Java would requiere to pass it ASTs as arguments, and return the desired code transformation as an AST. What I don't understand is why inside the implementation of the '

20:36 justin_smith: lavokad: same truncation again, just give us the rest

20:36 kristof: the same fiasco is happening in #lisp.

20:38 justin_smith: I wonder who decided users on clojure would be good targets for spam pms in spanish

20:38 *on #clojure

20:38 lavokad: that's strange I see the msg all right..must be my irssi client

20:39 justin_smith: well anyway the rest of us don't see the end of the question, so we don't know what the question is unless you share the second half with us

20:40 lintomas: join #clojure

20:40 Hi, I'm strugling to understand about some concept related with macros. Post I've read say that Lisp macros aren't viable, possible in Java because of java doesn't provide the developers with the access, neither the syntax to its ASTs. That the way to implement a macro in Java would requiere to pass it ASTs as arguments, and return the desired code transformation as an AST. What I don't understand is why inside the implementation of the

20:41 kristof: justin_smith: We kicked oooooio on #lisp. If you're an op, you should kick him here too.

20:41 justin_smith: I am not an op, but technomancy is one

20:42 lavokad, how many times are you going to show us the first half of that question without the rest of it?

20:42 Vfe: its a mystery for us to solve!

20:42 Guest52748: justin_smith: he quit

20:43 justin_smith: Vfe: if I wanted to answer questions where the first puzzle is what the actual question is, I wouldn't have broken up with my girlfriend last week

20:43 lavokad: :)

20:43 sorry now i see

20:43 there is a restriction on number of characters

20:44 Bronsa: lavokad 510 chars

20:44 kristof: I remember my first time using IRC.

20:44 lavokad: hhaha

20:44 Vfe: justin_smith: hah, got me there.

20:44 lavokad: yeah sorry

20:44 kristof: I shouted "Hello?!??! Can anyone read this?" like 20 times in some developer channel.

20:44 ...despite having used irc for many years, I did the same thing I used urbit.

20:45 lavokad: Hi, I'm strugling to understand about some concept related with macros. Post I've read say that Lisp macros aren't viable, possible in Java because of java doesn't provide the developers with the access, neither the syntax to its ASTs. That the way to implement a macro in Java would requiere to pass it ASTs as arguments, and return the desired code transformation as an AST. What I don't understand is why inside the implementation of the '

20:45 'supposed java macro' must we talk in AST language? Wouldn't that inside code be already a AST because it was parsed? As an example, this could be the definition of java unless macro: unless(e,f) {if (e) null else f;}

20:45 Vfe: success!

20:45 gfredericks: oh man I thought this whole time we were going to say something about the implementation of quote

20:45 kristof: hahahahah

20:45 justin_smith: haha

20:46 lavokad: and then calling something like this: unless('false, 'System.out.println("lalala"));

20:46 justin_smith: lavokad: the issue is, we want a data structure that we can manipulate. Java code is not a data structure (other than an array of characters I guess) so we cannot do any powerful manipulation of it

20:47 lavokad: compare to a lisp, where we get a tree representing the nested invocations making up the form - then we can use standard tree walking and tree manipulation algorithms to make new code

20:47 kristof: lavokad: ^ The structure is what's important. See Rust for what non lisp macros would look like. You have to specify types like expr (expression)

20:47 justin_smith: lavokad: this is much more powerful (and less error prone) than simple string substitution

20:51 lavokad: and yes, it likely becomes an AST inside the java compiler as it is parsed, but how would your code access that tree without rewriting the compiler?

20:52 how would you deal with the fact that different java implementations are allowed to use totally different data structures in their internal representations - maybe an AST, maybe not - it's not part of the java API so you have no promise of portability at all

20:52 AeroNotix: https://github.com/AeroNotix/lispkit hey I'm working on a browser implmented in Lisp

20:52 http://zerolength.com/posts/Introducing-Lispkit.html

20:55 kristof: doesn't everyone just use hotspot?

20:56 justin_smith: kristof: some people use openjdk (especially on commodity vms like aws / beanstalk)

20:57 AeroNotix: I use openjdk for development

20:57 lavokad: justin_smith: ty! However I dont get it. In my unless example: unless is a 'macro'. After being parsed, its body is AST. It gets unevaluated args, and substitutes body's params with them in that AST

20:57 AeroNotix: and we deploy on hotspot

20:57 kristof: lavokad: The real answer is that Java very well could have macros if that was important to them. You just need datatypes for "code". The point is that they don't provide those utilities to you.

20:57 I'm sorry, by them, I meant Oracle.

20:57 justin_smith: lavokad: that is not an AST because there is no tree in what you present to us whatsoever

20:57 it's a string of text

20:58 kristof: lavokad: And you also need a distinguished macroexpansion time during compilation. That is also not available to you as a programmer.

20:59 AeroNotix: lavokad: why don't you try to write a couple of lisp macros and see

21:00 kristof: lavokad: The lisp/clojure compiler gobbles up your text representation of code and reads everything, which turns it into a graph of symbols. Then, it goes through and "expands" macros, which take trees of symbols and produce new trees of symbols.

21:03 justin_smith: a C style macro (the weak kind) get's an input that's something like ['m' 'y' '_' 'm' 'a' 'c' 'r' 'o' '(' '1' '+' '1' ')' ';']; a lisp style macro (the powerful kind) gets an input like ['my-macro' ['+' '1' '1']] - you can walk that, and grab children as subtrees - you get extra structure that simplifies what macros need to do

21:03 gfredericks: ,(defmacro backwards [expr] (clojure.walk/postwalk #(cond-> % (seq? %) reverse) expr))

21:03 clojurebot: #<CompilerException java.lang.ClassNotFoundException: clojure.walk, compiling:(NO_SOURCE_PATH:0:0)>

21:03 gfredericks: ,(require 'clojure.walk)

21:03 clojurebot: nil

21:04 gfredericks: ,(defmacro backwards [expr] (clojure.walk/postwalk #(cond-> % (seq? %) reverse) expr))

21:04 clojurebot: #'sandbox/backwards

21:04 gfredericks: ,(backwards ((1 inc) 3 7 *))

21:04 clojurebot: 42

21:04 justin_smith: yeah, good luck doing that with string substitution

21:05 gfredericks: bonus points if you rename it from "backwards" to "reverse-polish"

21:09 gfredericks: ,(defmacro flaaten [expr] (flatten expr))

21:09 clojurebot: #'sandbox/flaaten

21:09 gfredericks: ,(flaaten (+ 1 (2 (3) 4 5 5) 2))

21:09 clojurebot: 22

21:10 lavokad: justin_smith: kristof, if I passed an if construct to an 'imaginable' java macro as an arg, and then return it in the macros body, it would still need the parsing step, that's why AST access and syntax knowing would be requiered, true?

21:11 to return directly an AST for following compiling step

21:12 justin_smith: a macro in lisp gets an ast as input, and outputs a new one

21:12 kristof: lavokad: No.

21:12 gfredericks: ,(defmacro squote [x] (pr-str x))

21:12 clojurebot: #'sandbox/squote

21:13 gfredericks: ,(squote (* 2 3 7))

21:13 clojurebot: "(* 2 3 7)"

21:13 kristof: lavokad: When you prefix a question like that with "imaginable java macro", you're basically saying "If Java had macros, Java would have macros."

21:13 justin_smith: gfredericks: this kind of stuff makes me wish clojurebot had macrolet (or the equivalent)

21:14 ,(require '[tools.macro :as m])

21:14 clojurebot: #<FileNotFoundException java.io.FileNotFoundException: Could not locate tools/macro__init.class or tools/macro.clj on classpath: >

21:14 kristof: gfredericks: Should have named it sexquote

21:16 lavokad: Here's the answer to your question again, in brief. Java can have macros, but it would need a macroexpansion phase and a canonical reprsentation of syntax objects. That representation could be an AST, or it could be distinguished objects, whatever.

21:16 lavokad: But it doesn't, and it never well.

21:16 lavokad: ok than I already get

21:17 ty

21:17 :)

21:17 kristof: lavokad: And that macroexpansion phase would be *before* compilation but *after* parsing.

21:17 lavokad: C macros are during parsing. That's the big difference.

21:17 gfredericks: ,(defmacro with-letters [expr] `(let [~@(mapcat (fn [i] (let [sym (-> i char str symbol)] [sym (list 'quote sym)])) (range 97 123))] ~expr))

21:17 clojurebot: #'sandbox/with-letters

21:18 lavokad: and there also reader-macros, which I've that clojure does not have for security reason or smth

21:18 gfredericks: ,(with-letters (let [x (* 2 3 7)] [x y z]))

21:18 clojurebot: [42 y z]

21:18 justin_smith: lavokad: they exist, for things like custom data literals, but we don't use them the way common lisp does

21:19 lavokad: you can recognize them because they usually start with #

22:21 bbloom_: ,(let [{:keys [:foo/bar]} {:foo/bar 123}] bar) ; when did this happen?

22:21 clojurebot: 123

22:21 bbloom_: so nice.

22:22 justin_smith: cool, I didn't know that worked

22:23 bbloom_: apparently that's new in 1.6

Logging service provided by n01se.net