#clojure logs

2016-01-26

03:48solatishmmm, from the erlang world i am familiar to doing this: `{_, _, bar} = foo()`, as in, a kind of pattern matching / variable construction in one. is this also possible in clojure? I know about core.match, but that seems to be more code bloat / not exactly the same
03:49MasseRsolatis: not exactly no. I think the best you can do is destructuring
03:49solatisok
03:49MasseRFor example if you have a list with 3 elements, you can destructure it into variables
03:49MasseRBut no full blown pattern matching
03:50solatisi think that's sufficient for what i want
03:50solatisseems like "destructuring" was the term i was looking for
03:53kwladykasolatis https://gist.github.com/john2x/e1dca953548bfdfb9844
03:54solatiskwladyka: thanks!
03:55solatis(let [{a :a d :d} my-hashmap]
03:55solatis (println a d))
03:55solatisthat seems to do exactly what i want!
03:56ridcully_there is also {:keys [a d]} if you just want the same names
03:58noncomhttp://emojilisp.com/
03:58autogen_Hey guys. I went to a clojure meetup and I suppose that's got me pumped to use clojure more. I wonder if there's any kind of live-programming interface for music composition and the likes
03:59CStormhaha noncom
03:59noncomautogen_: sure, there's like overtone, did you try it?
03:59noncoma new era of visual programming, right :D
03:59CStormspeaking of meetups, anyone going to clojured in berlin next month? im looking forward.
03:59autogen_I'll check it out :D
04:00noncomautogen_: also https://www.youtube.com/watch?v=wDcN7yoZ6tQ
04:01noncomautogen_: and https://www.youtube.com/watch?v=M-s1mIp1DQk
04:01noncomautogen_: well, and google/youtube has many videos on this kind of stuff
04:02noncomautogen_: i also look at the minim java sound library and some time in the past i also looked into the beads java library
04:14kenrestivoautogen: overtone
04:20autogen_so much.. much gratitude! :D
05:54neoncontrailsHaving trouble understanding how string/replace works. Can you construct a regex pattern dynamically?
05:54neoncontrailsSomething like this doesn't work
05:54neoncontrails,(str/replace ":K:FOO1FOO" #(apply str "(?<!:)" "FOO") ":FOO2")
05:54clojurebot#error {\n :cause "No such namespace: str"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: No such namespace: str, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "No such namespace: str"\n :at [clojure.lang.Util runtimeException "Util.java" 221]}]\n ...
05:55luma,(str/replace ":K:FOO1FOO" (re-pattern (str "(?<!:)" "FOO")) ":FOO2")
05:55clojurebot#error {\n :cause "No such namespace: str"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: No such namespace: str, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "No such namespace: str"\n :at [clojure.lang.Util runtimeException "Util.java" 221]}]\n ...
05:56luma,(clojure.string/replace ":K:FOO1FOO" (re-pattern (str "(?<!:)" "FOO")) ":FOO2")
05:56clojurebot":K:FOO1:FOO2"
05:56neoncontrailsluma: ah ha! Thank you
06:03spuzluma: what is the re-pattern call doing?
06:04spuzhmm i think i see why you are building the pattern with (str) - i guess you want to replace "FOO" with a variable
06:05neoncontrailsspuz: that's the idea, yeah. I got it working with re-pattern with a small modification
06:07neoncontrailsThis won't compile here without the dependencies, but it does basically the same as the above just mapped over a vector of substrings: (str/replace word (re-pattern (str "(?<!:)" (first substrings))) (apply str (first (cmudict (first substrings)))
06:07m1dnight_How can I check if, in Clojail, the result in a sandbox or a value?
06:07m1dnight_Im thinking of istypeof operations..
06:14owlbirdhow to use a local nexus as repositories, I didn't find a clear introduction. It seems lein will download some jars from maven' cental and others from clojars.org ?
06:14owlbirddo I need to config serval mirros in projects.clj ? or ~/.lein/profiles?
06:15george_hi, im wondering if anyone can help me find a sollution to a UVA problem online. I have to find a few different ways of doing the problem but im completely new to clojure if someone could help me with one sollution i might be able to figure out other methods of doing it
06:15george_its the problem here: https://uva.onlinejudge.org/external/5/571.html
06:24ridcully_owlbird: have a look at `lein help sample` and look for `:repositories`
06:27m1dnight_,(def x 5)
06:27clojurebot#'sandbox/x
06:27m1dnight_,x
06:27clojurebot5
06:27m1dnight_,source
06:27clojurebot#error {\n :cause "Can't take value of a macro: #'clojure.repl/source"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Can't take value of a macro: #'clojure.repl/source, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Can't take value of a macro: #'cl...
06:28chaos_ip cloak
06:28m1dnight_This is lazybot, right?
06:29george_anyone able to help me with finding a sollution to this problem in clojure? https://uva.onlinejudge.org/external/5/571.html
06:35m1dnight_Hm, I cant seem to spot it in the code of lazybot either, how the sandbox is persisted.
06:37MJB47its not lazybot
06:37MJB47its clojurebot
06:37MJB47https://github.com/hiredman/clojurebot
07:21CStorm,(+ 1 1)
07:21clojurebot2
07:21CStormthats pretty cool.
07:22qsysCStorm: did you expect to see 3 as a result? :p
07:22CStormhaha
07:23CStormjust havnt seen the bot before
07:23CStormthats why
07:23qsys:)
07:25oracle123how to pickup 2 element from a map? such as from {:a 1 :b 2 :c 3}, I want to get the element for :a and :b, so the result should be [1 2]
07:25schmir(juxt :a :b)
07:26justin_smith,((juxt :a :b) {:a 1 :b 2 :c 3})
07:26clojurebot[1 2]
07:26justin_smith,(map {:a 1 :b 2 :c 3} [:a :b])
07:26clojurebot(1 2)
07:26oracle123great. thanks :
07:27oracle123map is easier to understand.
07:27justin_smith,((juxt inc dec) 0)
07:27clojurebot[1 -1]
07:28justin_smith,((juxt first last) "hello")
07:28clojurebot[\h \o]
07:29oracle123ok, thanks for the example, understand now.
07:34lokienwhich function is first called in comp?
07:36ridcully_,((comp #(doto :a (println "second" %)) #(doto :b (println "first"))))
07:36clojurebot:b first\n:a second :b\n:a
07:39lokienso, lifo? thanks
07:44justin_smithprinceso is gone, but their code has been running in criterium for 9.5 hours and counting
07:44justin_smithamazing
08:02lokienjustin_smith: what does his code do?
08:02noncomjustin_smith: who's that?
08:02noncomm1dnight_: afaik there was something about clojail
08:09justin_smithlokien: (crit/bench (eval '(defn f [x] (+ 1 x))))
08:09justin_smithlokien: I've been benchmarking it for about 10 hours now
08:09justin_smithstill going
08:09Bronsajustin_smith: what
08:09justin_smithI'm guessing this is a bug in criterium, but now I'm just morbidly curious how long it will keep on
08:10lokienjustin_smith: and your cpu is on 100% constantly?
08:10justin_smithBronsa: criterium has been using 100% of 1 of my cpus for about 10 hours running that
08:10justin_smithlokien: one of my 8, yes
08:10Bronsalol
08:10Bronsajustin_smith: do you have a vague idea of how many classes you created during that time?
08:11justin_smithBronsa: I'm guessing eval/defn must do something that prevents criterium from deciding it's done
08:11justin_smithBronsa: rofl, I'm sure it's millions at least
08:11opqdonutdid you grab a thread dump yet?
08:11justin_smithopqdonut: oh, good call, one moment
08:14justin_smithopqdonut: thread dump https://gist.github.com/noisesmith/ed887bd7a002eb507540
08:14lxsameerhow can i run some code on process termination ? ( i want to stop my services properly )
08:15lokiennot so scary
08:15opqdonutjustin_smith: right, so it's actually doing the def
08:15justin_smithlxsameer: you can add a shutdownhook via the Runtime class, but be aware that some shutdowns will bypass this hook https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html
08:15opqdonutlxsameer: well the jvm has exit hooks, but the real answer is to use with-open and the java Closeable interface
08:16owlbirdridcully_: I add :mirrors {"central" {..}} to ~/.lein/profiles.clj, then use lein new compojure web, all packages were downloaded from my local mirrors, It works fine. But while I executed 'lein ring server' in the project directory, packages were downloaded from clojars.org again.
08:16justin_smithopqdonut: yup, like I asked it to
08:16opqdonutyeah, just checking
08:17owlbirdIf I add :mirrors to project.clj, then an exception happened 'Multiple mirrors configured to match repository'
08:17lxsameerjustin_smith, opqdonut what's with-open ? can you point me to right direction please
08:18opqdonutlxsameer: https://clojuredocs.org/clojure.core/with-open
08:18justin_smithopqdonut: with-open won't do any cleanup that wouldn't be done automatically at vm shutdown, it's just useful for making sure you don't run out of handles
08:18justin_smithopqdonut: I don't see how it helps at all with the vm shutdown case
08:19justin_smithwhen the vm shuts down, the OS takes back all file handles and all memory, whether you explicitly release it or not, even if the vm fails to let it go
08:20opqdonutI mean if lxsameer has some code he wants to run on shutdown, and that code is related to some resource (db connection, etc), it might make sense to have a Closeable object for it
08:20justin_smithshutdown hooks are for the kinds of cleanup that the OS can't predict or provide
08:20justin_smithopqdonut: but it's going to close on shutdown, there's no way it would not be
08:20opqdonutjustin_smith: yeah but maybe he wants to log something, flush something, commit something, whatever
08:20justin_smithclean shutdown of resources is great if you want to stay running a long time though
08:20opqdonutthe problem with exit hooks is that they're not very composable
08:21justin_smithopqdonut: sure, with open helps with none of those, that's why you add a shutdown hook
08:21lxsameerjustin_smith, I'm currently use runtime hook, but since it runs on another thread it seems it would have some problems, let me show you some code
08:21justin_smithopqdonut: why would you need to compose them?
08:21lxsameerjustin_smith, http://dpaste.com/29N3DHV
08:21lxsameeropqdonut, ^
08:22opqdonutjustin_smith: perhaps composable is the wrong word, but they're global and that hurts e.g. testability
08:22justin_smithlxsameer: as long as you are aware that there are kinds of shutdown that will prevent that hook from running, that looks fine to me
08:23lxsameerjustin_smith, cool, thanks
08:23justin_smithopqdonut: so what you would do is have a with-open around some resource, and then put the cleanup code after it in the same function body?
08:24opqdonutcleanup code is in the .close method of the resource
08:24justin_smithwhose cleanup code?
08:24justin_smithso you reify closable?
08:24opqdonutyeah
08:24justin_smithinteresting
08:25justin_smithopqdonut: doesn't this end up being try/finally with no catch clause?
08:25opqdonutyes
08:25justin_smithbut with-open looks nicer?
08:25opqdonutyeah, and the code related to a resource stays in one place
08:26opqdonutanyway, something like (defn -main [] (with-open [aserver (make-aserver) bserver (make-bserver aserver)] (wait for shutdown)))
08:26justin_smithinteresting
08:28opqdonutc++-style resource management, kinda
08:28opqdonutour code is long-running and has a lot of resources (memory on native heap, sockets, shared memory) so we use that pattern a lot
08:29opqdonutusually the finalizers of the resource objects assert that the resource has been closed, as well
08:29opqdonutso we can test resource handling
08:29justin_smithopqdonut: shared memory cleanup is one of those cases where explicit cleanup is really called for
08:29justin_smith(at shutdown that is)
08:30opqdonutyeah but for e.g. running integration tests you really want to be able to start and stop the system multiple times per jvm
08:30opqdonutso exit hooks won't cut it
08:30justin_smithoh yeah absolutely
08:31justin_smithI guess I was very literally answering the "how to run something on exit", including the criteria "this clearly is only about those things that you actually need to clean up on vm exit so you can skip the stuff that is guaranteed to be cleaned up anyway"
08:32opqdonutalso, I've had deadlocks with exit hooks
08:32opqdonutthere was code that calls exit when an exception bubbles up high enough
08:32opqdonutthere were multiple threads
08:33opqdonutexit hook wanted to shut down the threads
08:33justin_smithouch
08:33opqdonutso when an exception gets propagated to two threads...
08:34opqdonutgetting rid of the hook and using try-finally (i.e. with-open) for the cleanups solved the problem
08:34opqdonutoh right, temporary files is another case where explicit cleanup is needed
08:34opqdonutespecially if they're large
08:34justin_smithtrue!
08:35justin_smiththat's exactly what with-open is made for
08:35opqdonutmmh
08:35justin_smithalso, in our own product, we discovered the need for something like with-open for kafka topics
08:35opqdonutyeah, communication channels might need explicit shutdown
08:35justin_smithlike - "this code needs the topic, but it should be destroyed when we leave this scope"
08:36opqdonutyeah
08:36justin_smithwhich gets messy because topics are shared between vms, that's the point of them, but we can always give them a definitive owner in the app logic, so it should work out
08:37opqdonutownership is important yeah
08:37opqdonutand transferring ownership is hard
08:37justin_smiththough the previous iteration (my initial design) was using a smaller set of topics and routing on receipt - which has the advantage of not needing the tracking and cleanup, disadvantage of shared topics and routing
08:38justin_smith"just make new topics for stuff" was working great until we filled up kafka's disk drive though :P
08:38opqdonuthehe
08:39justin_smithbut come to think of it, this being kafka, those topics are effectively temp files (or we should be treating them as such)
08:43noncomhttps://hsto.org/files/710/547/32a/71054732a3c34fce82a1baafb7986ca8.png
08:58justin_smithnoncom: but aren't microservices one of the easiest ways to get clj into production?
09:05winkjustin_smith: don't give me ideas! :P
09:18jakedustis there a way to juxt method calls? Something like (juxt .getKey .getValue)
09:19lumayou need to wrap the method calls in an anonymous function
09:19luma(juxt #(.getKey %) #(.getValue %))
09:19jakedustoh, I see, thanks!
09:21engblomI know it is not recommended to use array, but for the sake of speed, I would in this case need to create an array of atoms, where each atom might be either 'nil' or 'clojure.java.io/output-stream', how would I do it
09:22engblom(make-array ....) wants a type.
09:23mpenet,(into-array [(atom nil) (atom 1)])
09:23clojurebot#object["[Lclojure.lang.Atom;" 0x42eac430 "[Lclojure.lang.Atom;@42eac430"]
09:23mpenetbut the whole thing sounds hairy tbh
09:25engblommpenet: I know. I would prefer to use just a hash map. I am making a gpio library for raspberry pi and with a map, 10000 writes takes 1.5 seconds. With vector it went down further to 1.3. Still I would need to get it even lower.
09:28engblommpenet: Currently, the library is able to handle 2-3 stepper motors before hitting the limit, when using rpi2. I do not have the rpi1, but some figures are saying that the gpio is about 2.5 times slower. That means just one stepper motor at full speed.
09:29engblomFull speed means about 14 rpm
09:29engblom(for 28byj-48 stepper motor)
09:31mpenetI am not really concerned about the array, but whenever I see lots of atoms I am suspicious.
09:31mpenetmaybe something that might be designed differently
09:32engblommpenet: https://github.com/engblom/gpio/blob/master/src/gpio/core.clj
09:32engblommpenet: It is the uggly output-streams in this file. (I know, that line looks just uggly)
09:34engblommpenet: The important functions using the output-streams are open-pin and write-value
09:35engblomIt is the write-value I would need to optimize as far as it is possible.
09:35engblomCurrently I am using only one atom (the whole vector) as vectors are, if I understood right, immutable
09:36engblomI suspect I could drop the use of atoms completely if I went with array...
10:06kwladykaPossibility to comment with #_ is so good.... genius invented this ;)
10:20justin_smithengblom: if you are using an array, why not just an array of output-streams where some can be nil?
10:21justin_smithyou wouldn't need anything inside it to be an atom
10:22justin_smithhaha, I just ssh'd to my home machine and that silly benchmark is still running (12 hours it's been going now)
10:24marianoguerrahi, I have an app that loads some deps from the classpath (JDBC drivers) it runs fine on the build but I can't find where to put them during development when I run "lein run", any help?
10:25justin_smithmarianoguerra: what are you using to manage your classpath?
10:25marianoguerrajustin_smith: mmmh, nothing explicit?
10:25marianoguerrajustin_smith: the run script when built adds the lib folder to the classpath
10:25justin_smithmarianoguerra: well, leiningen is primarily a tool for setting up the classpath
10:26justin_smithmarianoguerra: the expected usage is that things you want to be available during runtime should be declared as :dependencies in your project.clj
10:26justin_smithbut this also assumes they are available by some maven repo or cache
10:26marianoguerrajustin_smith: I know about reproducible builds and all that, that's why I clarified that they are jdbc drivers
10:27marianoguerraeach user has their own needs, I can't bundle all of them just in case
10:27justin_smithmarianoguerra: OK, then just put them in your dependencies
10:27justin_smithif you don't deploy them, put them in the :development profile
10:27justin_smiththat will ensure they aren't bundled with a deploy
10:28justin_smithmarianoguerra: sorry, that's :dev as shown here https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L160
10:29marianoguerrajustin_smith: will try that, thanks
10:30justin_smithmarianoguerra: both keys there are applicable actually - anything under :resource-paths is added to your classpath, and you can also have normal dependencies specific to a profile
11:40justin_smithtfw that criterium benchmark you started running 13 hours ago is still using 100% CPU on one thread
11:43ashnurhow do people handle user input validation in clojureland?
11:44cap10morganashnur: We use Plumatic Schema (formerly Prismatic) https://github.com/plumatic/schema
11:46ashnurthanks
11:47cap10morganashnur: that's a building block that is solely focused on the data structures, not any UI aspects. other libs get into web form UIs more if that's what you want.
11:49ashnuryeah, my issue is that our java backend is sending me validation errors such that from js it looks something liek "res.body.errors[0].exception.validationResults[0]" and that is an object which has validatedObjectType, status, failedRegexRules, failedNullChecks, failedDataValueValidations
11:50ashnurand here i was hoping that if we use graphql this is going to be better. now it is too late
11:55engblomReally suprising: java-array is slower than vector... about 11-12 times slower
11:55engblomI was expecting an array to speed up my code, but it is slower now...
11:56justin_smithengblom: slower to do what?
11:57Bronsaengblom: you're probably doing a lot of reflection
11:57engblomWhat earlier too 1.3s now takes 12-13s
11:58engblomso 10 times slower
11:59engblomBronsa: What do you mean with "reflection"?
12:01justin_smithwhen clojure can't tell at compile time what the type of some variable will be, it compiles code that checks the type at runtime
12:01justin_smiththis type checking is reflection, and it is expensive
12:01justin_smithit's very slow
12:02engblomjustin_smith: Raspberry Pi got totally 54 GPIO "pins". Some are real, some are for checking up other things. So I am having a 55 items long array created by (make-array java.io.BufferedOutputStream 55). The purpose was to really quickly map gpio number to right output-stream.
12:02kwladykaengblom practical example http://clojure.wladyka.eu/#avoid_reflections
12:03justin_smithengblom: if you turn on the *warn-on-reflection* parameter, you can find what in your code might be reflecting
12:04kwladykaengblom but i suggest solution from my article, i doesn't mess with reflections in core on screen
12:04justin_smithoh, kwladyka 's link shows that, cool
12:04engblomThe only thing I am basically doing is (.write (aget output-streams gpio-number) (.getBytes "1\n"))
12:05Glenjaminhttps://github.com/technomancy/leiningen/blob/master/sample.project.clj#L259
12:05Glenjamin^ I like doing it that way
12:05justin_smithengblom: that's probably got at least one reflection happening (type of output-streams) if not more
12:05GlenjaminI suspect that .write is reflection
12:06kwladykaGlenjamin just check it, you have description how in my link
12:06kwladykaoh, not to you :)
12:07Glenjaminyup :p i'm just eyeballing
12:07kwladykasorry, i am just after whole day of work and i will work more :)
12:07Glenjaminouch
12:07kwladykabut now for my pleasure....
12:07kwladyka;)
12:17engblomHow should the reflection be made for (.write stream (.getBytes "1\n"))?
12:17engblomThe hint, I mean
12:18justin_smith(.write ^java.io.OutputStream stream (.getBytes "1\n"))
12:18justin_smithor you could give it the more specific type if you have it
12:21engblomThanks
12:28krrysishey
12:28krrysiswhats this channel about?
12:29krrysisanyone?
12:29clojurebotJust a heads up, you're more likely to get some help if you ask the question you really want the answer to, instead of "does anyone ..."
12:29krrysishi
12:29justin_smithkrrysis: as the topic says, the clojure programming language
12:29tomas`hi, I have this https://gist.github.com/anonymous/7c1915e9be6426b82de2 simple setup but I get an error of "no such namespace"
12:30justin_smithtomas`: I would not expect cljsjs/google-maps the project to provide a cljsjs.google-maps namespace
12:31tomas`https://github.com/cljsjs/packages/wiki/Using-Packages
12:34justin_smithtomas`: https://github.com/cljsjs/packages/tree/master/google-maps there's nothing in there that defines a cljsjs.google-maps namespace
12:42engblomhttp://pastebin.com/x0yWQcbd <---something is wrong. I get "Exception in thread "main" java.lang.IllegalArgumentException: No matching method found: flush for class java.io.BufferedOutputStream"
12:46backnforthNewbie question: When I run "lein run", my program runs fine, but after the program is finished I get a "Exception in main.. Cannot find anything to run for" error message.
12:46backnforthHow can I fix this potential error?
12:52justin_smithbacknforth: umm, what's the actual error message?
12:52justin_smithbacknforth: my suspicion is that you have top level side effects but no -main for lein run to launch
12:53justin_smithengblom: are you sure it's a BufferedOutputStream ?
12:57backnforthI have a main: projectName.core is my project.clj
12:58justin_smithbacknforth: does projectName.core have a function called -main ?
12:58justin_smithor does it just have side effects in the top level code?
21:57kenrestivowell there is the bureaucracy of setting up a lein project, bringing in dependencies, and organizing namspaces...
21:57kenrestivowhich compared to, say, firing up ipython, is maybe a bit more heavyweight for small scripting-type tasks.
21:58kenrestivobut yeah, once you go clojure you might never want to go back :)
23:23macroliciouswhy does #{1 2 1} produce a duplicate key error but (hash-set 1 2 1) does not?
23:24justin_smithmacrolicious: one is a reader macro for a literal, the other is a function call
23:24macroliciousok, thx
23:25justin_smithmacrolicious: for example you might want to call (apply hash-set som-coll) and you don't want an error at runtime if there is a dup
23:25justin_smithbut for #{} it's always a compile time literal you can fix
23:27macroliciousah ok
23:38Malnormalulostrictly speaking I don't think #{} is a reader macro
23:38Malnormaluloit's just a literal
23:45justin_smithMalnormalulo: anything starting with # is a reader macro
23:46justin_smithMalnormalulo: as documented under "Macro characters" here http://clojure.org/reference/reader
23:53Malnormaluloweird that the read-string function doesn't parse it into something else, then
23:54justin_smithMalnormalulo: like most # dispatched reader macros, its printed form is the same as the dispatched form
23:54justin_smithbut all those things starting with # are reader macros, in fact clojure doesn't let you make new reader macros that don't start with #
23:55Malnormalulohuh
23:55justin_smithclojure reader dispatch is not like common lisp reader macros, it's much more limited
23:55justin_smiththere's a good argument for maybe not using the term, but that's already too late, clojure.core already adopted the term
23:56MalnormaluloI'm not familiar with common lisp. I just am surprised to see something termed a macro that doesn't preprocess into other code.
23:56justin_smithit's custom reader code, which runs before anything else, including regular macros
23:57justin_smithusually used for creating data literals
23:57justin_smitheg. when you create a record, clojure creates a reader for that record automatically
23:57justin_smithsome of them don't round trip - eg. #()
23:58justin_smith,'#(+ % %)
23:58clojurebot(fn* [p1__25#] (+ p1__25# p1__25#))
23:58justin_smiththat one is much more obviously a macro - the printed form is very different from the input form
23:58Malnormalulothat's the sort of behavior I'd expect from a macro
23:58justin_smithright -the difference with the data literals, is they were defined to print their own macro
23:58justin_smithit's clever and very convenient :)