#clojure logs

2016-03-05

00:51will_smHow should I make "structs" in clojure?
00:51will_smshould I just use a hashmap?
00:52skelternetwill_sm: think so
01:01skelternetcould use a record but it will include most funcs of a map.
01:02skelternetsorry not staying longer. good night
04:55ConfusionistHi, is there a way to get 'lein ancient' to also report what plugins and dependencies in my .lein/profiles.clj can be upgraded?
05:43renlHi what libraries should I use for interprocess comma as well as distributed systems?
06:28spuz_Is there a better way to find the largest value in a sequence that is less than some value?
06:28spuz_, (apply max (filter #(< % 10) (range 1 19)))
06:28clojurebot9
06:53Confusionistspuz_, in general there isn't, but if you know the sequence is ordered you can exploit that. E.g. in the example case you can replace 'apply max' by 'last'
06:53spuz_Confusionist, yeah thanks
06:53spuz_or drop-while and first I guess
06:54Confusionistor reverse and find the first entry matching a predicate: that could also be significantly faster
08:04OscarZi cant get lein repl to open.. i probably messed up something in my project.clj.. just getting message "Logging initialized..."
08:05OscarZany ideas what are common causes for repl not to start ? after a timeout it fails with error "REPL server launch timeout"
08:07OscarZhmm.. it loads the namespaces i suppose, maybe im doing something foolish somewhere in my .clj files
08:38OscarZhmm i suppose i need to find out what lein repl actually does...
08:58justin_smithrenl: manifold from ztellman ties those things together, and has nice things like flow control and back pressure too
08:59justin_smithOscarZ: it starts an nREPL server then loads your :main namespace
08:59renlthanks
09:00justin_smithOscarZ: I think your best bet is to run lein clean, then run 'lein run -m clojure.main' then that launches a vanilla clojure.main repl
09:00justin_smithOscarZ: in that repl (require 'my-main.ns) and watch for errors
09:00justin_smithI bet that will be informative
09:01renlis manifold like a message queue?
09:01OscarZjustin_smith, thanks ill try that.. forgot to mention that i have a dev profile with user.clj.. but it has nothing in it except requires
09:02justin_smithrenl: no, it's a utility library with many facilities relating to message queues
09:03justin_smithOscarZ: a clojure.main repl should also end up loading your user.clj - but in my experience running clojure.main is more likely to expose errors that are silent in lein repl in some cases
09:05OscarZok.. i think this is an issue with some of my code that runs when the namespaces are loaded
09:10renlmanifold doesnt handle the actual socket programming right? is aleph the goto library for all things socket?
09:10justin_smithrenl: aleph is good (and it already pulls in manifold by default)
09:12justin_smithI think I misinterpreted your question because of the "as well as" - manifold can help do coordination inside one vm as well as coordination between vms, whether on the same host or different hosts, and can be used to tie socket comms together with distributed stuff
09:12justin_smiththough in java IPC tends to fall back to the same stuff you would use for distributed, because there's not much for portable IPC and java aims to be portable
09:13renlnod thanks
09:13justin_smithI should say "on the jvm" and not "in java" but you probably get that's what I meant
09:15renlyup
12:02arkhis there a way to limit/truncate stacktrace length when using tools.namespace and (refresh)?
12:04arkhthe interesting parts are usually the first 30 lines or so but some stack traces get in the ballpark of 120 lines
12:25cortexmanwhat's a stateful transducer?
12:29arkhcortexman: http://stackoverflow.com/questions/26506689/what-is-a-stateful-transducer
12:55cortexmanarkh, is it the same as a finite state tranducer?
12:55cortexman*transducer
13:04arkhcortexman: an FST is a bit more than a stateful transducer though to be honest I've never used one. Looks interesting though! I'm reading up on it now
13:04arkhe.g. https://github.com/structureddynamics/clj-fst
13:46spuz_, (-> (range 10) (partial map even?))
13:46clojurebot#object[clojure.core$partial$fn__4761 0x4e1b30c4 "clojure.core$partial$fn__4761@4e1b30c4"]
13:46spuz_why does that not return [0 2 4 6 8] ?
13:48TMA,(macroexpand '(-> (range 10) (partial map even?)))
13:48clojurebot(partial (range 10) map even?)
13:49TMAspuz_: that's why
13:49spuz_ah right
13:50spuz_if I want to use -> and a map, how can I do it?
13:50TMAspuz_: what do you want to accomplish?
13:50spuz_I want that first example to return a list of even numbers
13:51spuz_and to use the threading macro
13:51TMAwhy?
13:51clojurebotTMA: because you can't handle the truth!
13:53TMAspuz_: if you want the even numbers, you might be better of with (filter even? (range 10)) or some such
13:53spuz_TMA, ok maybe it would be more accurate to say, I would like to learn how the -> macro works
13:54TMAnow you are talking :)
13:54TMA,(macroexpand '(-> a (b) (c)))
13:54clojurebot(c (b a))
13:55TMAspuz_: it is quite easy: (a) (-> form) is just form
13:56TMAspuz_: (-> form (head rest...)) is (head form rest...)
13:56spuz_TMA is it possible to use -> with (map f) ?
13:56TMAspuz_: and finally (-> form (head rest...) others...) is (-> (-> form (head rest...)) others...)
13:57TMAspuz_: indeed it is. but the result might be very different from what you might expect
13:58spuz_is it possible to use it in a way that does what I expect?
13:58spuz_or do I have to use ->> ?
13:58TMAspuz_: (-> X (map f)) is the same as (map X f)
14:00burhanloey(->> (range 10) (filter even?)) I guess?
14:02TMAspuz_: also, map yields a sequence of the same length as its second argument, which is very unwieldy if you like to filter out some elements
14:03TMAspuz_: however, with proper obfuscation it can be done
14:03spuz_I meant to use filter, not map
14:03spuz_poor exampe
14:03spuz_example*
14:04bacon198`I found it hard to understand threading at first
14:04bacon198`you need to think in terms of (-> <context> <expressions...>)
14:04bacon198`<context> gets placed as the first argument of each expression
14:05bacon198`errr
14:05bacon198`the result of that previous expresssion gets passed on to the next one
14:05bacon198`as the first argument of the expression
14:06will_smSo I can't put a docstring in a defonce?
14:06TMA,(apply concat (-> (range 10) (((fn [f] (fn [a b] (f b a))) map) (fn [x] (if (even? x) [x] [])))))
14:07clojurebot(0 2 4 6 8)
14:07TMAspuz_: see? it can be done with -> and map
14:07TMAspuz_: with a bit of magic
14:08spuz_um
14:08spuz_that is going a bit too far for me
14:12TMAspuz_: please do not do that ever in production code
14:13TMAspuz_: from the inside ((fn [f] (fn [a b] (f b a))) map) is a function that is exactly like map, except when you call (map A B) you need to call (abomination B A) for the same result
14:14spuz_hah ok i see
14:14TMAspuz_: (fn [x] (if (even? x) [x] [])) is a function that returns [x] for even x and [] otherwise
14:14spuz_isn't there a function that does that for you in clojure?
14:14spuz_i.e reverses the order of arguments
14:15TMAit might be there
14:17TMAspuz_: and finally the (apply concat ...) merges the [[0] [] [2] [] [4] [] [6] [] [8] []] into (0 2 4 6 8)
14:17justin_smithTMA: that could be mapcat btw
14:17spuz_in haskell there is flip
14:18justin_smithin clojure I would do (fn flippy [f] (fn [& args] (apply f (reverse args))))
14:19justin_smithbut that isn't a thing defined in clojure.core
14:19TMAjustin_smith: I have already said that I do not know clojure ;) therefore I was ignorant of mapcat
14:19justin_smithaha
14:20TMAI am using it now and then, but I do not know it. It is so much better than java, I can be more productive even without knowing it
14:23TMAspuz_: personally I do not use -> or ->> or any of the ilk. they make code too cumbersome to figure out for me. However, that means there is a lot more deply nested parentheses in my code, which I personally do not abhor as much as the average programmer
14:23spuz_heh
14:23spuz_I have not used them so much so far
14:24spuz_but for this particular case they make a lot of sense
14:24SomelauwI see a lot of clojure programmers use unicode for variable names. What is your favourite method of doing unicode input?
14:25SomelauwI mean, how do you enter weird chars like → or ǽ or Greek λ or is that still a bad idea?
14:26justin_smithTMA: wait, I just realized your silly thing above was just (filter even? (range 10))
14:26justin_smithSomelauw: probably mostly people are using emacs
14:27justin_smithSomelauw: either something that automatically translates certain names, or gives shortcuts for inserting favorite chars (though in emacs you can insert any char by name with M-x insert-char)
14:27TMAjustin_smith: yes. the goal was to implement it using -> and map; in particular -> had to be used
14:27justin_smithoh
14:28justin_smith,(->> (range 10) (mapcat #(when (even %) %)))
14:28clojurebot#error {\n :cause "Unable to resolve symbol: even in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: even in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: even in this co...
14:28justin_smithergh
14:28justin_smith,(->> (range 10) (mapcat #(when (even? %) %)))
14:28clojurebot#<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long>
14:28justin_smithoh right
14:29justin_smith,(->> (range 10) (mapcat #(when (even? %) [%])))
14:29clojurebot(0 2 4 6 8)
14:29TMAjustin_smith: ->> was expressly forbidden, hence the argument flipping abomination
14:30justin_smithoh, man, I should have just read the scrollback
14:30Somelauwjustin_smith: ah, in vim there is ctrl-k. I just think I want this system-wide or something
14:30TMAit was fun to design it though. :)
14:31SomelauwIf emacs also uses RFC 1345, vim and emacs might actually be using the same mappings
14:31justin_smithSomelauw: emacs uses the full written name of the char (with tab completion) for insert-char at least
14:31spuz_Is there a better way to write this function? https://www.refheap.com/a3fa8bcb058f49e845a7dc0e5
14:32spuz_I am not entirely sure why I have to use map, apply and str to convert the partitioned values back into a string
14:32justin_smithSomelauw: thanks for the info, I just switched to vim a week ago (I had been using evil mode for wrist reasons, and I figured I might as well try the real thing)
14:33justin_smithSomelauw: oh cool, C-kl*
14:50OscarZhow does clojure namespaces work.. say i have some core namespace that has some namespaces that are :required at the top of the file.. does it load and run them recursively in the order then ?
14:54hiredmanbecause a string becaomes a seq of characters, and partition partitions that seq of characters in to a seq of seqs of characters, and join takes a collection of strings
14:55justin_smithspuz_: also, unlike in haskell, in the jvm a list of chars is not a string
14:59OscarZim using the ns :require in dev/user.clj to require some namespaces, one of them is db.clj where im doing some db initialization work .. for some reason when running lein repl this init gets stuck
14:59justin_smithOscarZ: when you require a namespace, all top level code is run
15:00justin_smithso if there's something at the top level of the namespace that would block or error, require will make that blocking or error happen
15:00OscarZbut if i comment the particular namespace out from ns, lein repl starts.. and if i then run (require 'db) it works fine
15:00justin_smithhmm
15:00OscarZseems like some kind of race condition or something..
15:01justin_smithrequire doesn't do anything concurrent, (but if you have async stuff at the top level of your namespace that has side effects I'd expect all kinds of problems)
15:04OscarZno async stuff as far as i know :)
15:08OscarZsomehow related to repl and its loading .. it works when repl is loaded and then i require the namespace..
15:15jumarwillharrison, you should be able to download it from http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey
15:16jumarjust look at the source code - you should find the link like http://videoh.infoq.com/presentations/09-sep-clojure-keynote.flv
16:00Somelauwjustin_smith: I admit that emacs insert-char is easier to use than vim digraphs. Maybe not faster, but definitely easier.
16:42Somelauwjustin_smith: I ported the emacs insert-char function to Python: https://pastee.org/3pwmc
16:43justin_smithSomelauw: so is that a plugin for dmenu? I think that's what I use as a launcher with i3 on my linux box
16:43justin_smithhonestly I forget what the program is called
16:44Somelauwyes, i3 uses dmenu in its standard config
16:45Somelauwnot completely finished, because it only prints the character, I need to insert it as well
16:48Somelauwunfortunately, xdotool key "!" doesn't work for me
16:56Somelauwjustin_smith: An ugly workaround, but it works if you call it like this: python insert-char.py | xclip -i && xdotool key "shift+Insert"
16:57rhg135Beats learning vimlang
16:58Somelauwand instead of print, you need sys.stdout.write in the last line of my paste
17:11Somelauwblegh: it seems that in Python printing unicode works fine when printing to a console, but that an encoding is needed when piping to another process
17:12Somelauwso here is yet another version: https://pastee.org/t3w4c
17:14Somelauwrhg135: I could maybe rewrite it as a plugin for some fuzzy-completion plugin in vim, but now I have it system-wide
17:15SomelauwUnix says: DOTADIW but sometimes it's unclear which resposibility should be given to whom
17:15rhg135Somelauw: I think you can spawn subprocesses, they must be synchronous though
17:16rhg135r!stuff is useful
17:16Somelauwrhg135: i'm already doing that, I now have a small shell wrapper around python that can also be put in the code itself using subprocess
17:16Somelauwwhat is r!stuff?
17:17rhg135Insert the output of a command
17:18Somelauwin shell?
17:18justin_smithSomelauw: clearly what you need is to turn vim into a window manager
17:19rhg135Any executable
17:19Somelauwrhg135: can you give an example?
17:19Somelauwjustin_smith: that's what Emacs said
17:19rhg135:r!echo 1 would insert 1 in vim
17:20Somelauwoh, in vim
17:20Somelauwand I thought that needed a space between r and !
17:20rhg135Maybe it does
17:21justin_smithno, it doesn't
17:21justin_smith(just checked)
17:22rhg135justin_smith: actually vim already does a bit of window management
17:22Somelauwrhg135: :r !python insert-char.py prints the char after a newline for me
17:23justin_smithrhg135: right, my point was he was trying to get vim-style char insertion everywhere (thus the dwm thing...) and a vim solution only helps if all his other apps are inside vim
17:23justin_smithbut maybe I misunderstood the task
17:25rhg135Isn't this why input managers exist?
17:26Somelauwif an input-manager can do this or has a plugin system to do this or something that would be great
17:26rhg135Well, I wasted time getting uim working
17:27SomelauwFor some reason, gtk and qt use a different input than the rest of x
17:27rhg135Let's me bug people with infinite amounts of Greek letters
17:27Somelauwrhg135: How have you set uim up?
17:28rhg135I think I just launched it and set some variables from my profile
17:28Somelauwhow do you enter a greek char from uim?
17:29rhg135The arch wiki was useful here
17:29Somelauwat least in xim, you need to write your own .XCompose
17:29rhg135Compose key is how I do it
17:29rhg135C-S-u
17:29Somelauwbecause the standard composing have a very limited set
17:30rhg135Yup
17:30SomelauwI already made xim use vim digraphs using some script
17:34Somelauwthe arch wiki page about uim only talks about Japanese
17:37rhg135I looked at all the input manager pages
17:39Somelauwit might be that uim has more features than xim I don't know
17:39Somelauwrhg135: Is there anything xim doesn't do that you need?
17:39rhg135I couldn't get xim to work in some apps
17:41Somelauwyeah, gtk and kde use their own input methods by default for some reason, you could force them to use xim or uim
17:42rhg135I'll try that when I'm at my computer later
17:50Somelauw
17:51Somelauw
17:51Somelauwthat's supposed to be snowman
17:51Somelauwokay, played enough
18:09rhg135I see
18:23justin_smithyes, that was a snowman
18:26RedNifreHey there. First time using leiningen, I try to use Compojure by following this guide: https://adambard.com/blog/sinatra-docs-in-clojure/ but I get this error, what is the problem? http://pastebin.com/Xn54awdU
18:27justin_smithRedNifre: how did you add compojure to your dependencies?
18:27justin_smiththat error means that the clojure compiler could not find the compojure files
18:27RedNifregood question, the tutorial wasn't that clear so I improvised. One second...
18:28RedNifreAh, I'm pasting too much. Anyway, here is my project.clj: http://pastebin.com/mNyyRNaV
18:30RedNifreI did not follow the tutorial exactly, it said to run "lein new myapp" but I thought since that would create a library project where I surely want an executable I went with "lein new app myapp" instead. Was that wrong?
18:30justin_smithRedNifre: if the project.clj is what you shared, and it is in the directory with the project, lein should have downloaded compojure (or used the copy already on your cache)
18:31RedNifreI won't have a copy in my cache since this is the first time I use compojure. I should do "lein run" in the project directory i.e. the directory that contains the project.clj, right?
18:31justin_smithRedNifre: can you share the output of 'lein cp' - or at least check if compojure is actually in that output?
18:32justin_smithRedNifre: right
18:33RedNifreAh, never mind. It seems that the project.clj wasn't properly saved m/
18:33RedNifreSeems to work properly now, sorry.
18:34justin_smiththat would explain it
18:36RedNifreRegarding tutorials, I did not like "Clojure for the brave and true" at all. I heard "the joy of clojure" might be good, can you recommend it? Or what might be a good next step for me?
18:36justin_smithjoy of clojure is good, but it's not a slow intro
18:37RedNifreSounds good. I'm looking for something that is as in-your-face overwhelming as the Haskell tutorials.
18:41ridcullyif you are battle hardened in other languages i found clojure applied very nice
18:42justin_smithyes, that's a good one too
18:45RedNifreSo what's the theme of "joy of clojure" compared to "clojure applied"?
18:45justin_smithjoc gets more into the design philosophy, clojure applied has more about typical incidental things you should know if you are going to develop and deploy clojure
18:50RedNifreWell, the situation I find myself in is this: I write large things in Haskell (solid, difficult) and small scripts in Ruby (messy, easy). Clojure looks interesting to me because it's functional. I'm skeptical about the dynamic typing but I think I should give it a chance. Macros seem amazing, though the only use case I can think of so far would be Haskell's do-notation. What I find very fascinating is this "code is data" thing; edn is muc
18:50RedNifreh more elegant than json so the idea of writing config files in the same data format that I use to write the small tools that use them is appealing.
18:52RedNifreSo basically I wonder if Clojure can replace Ruby for me (I only use Ruby for small tools) and if that works out I might check how far it scales i.e. whether I can write code as robust as Haskell code but quicker (because of dynamic typing).
18:53RedNifreI'm not sure if I can judge those two books yet, but maybe I should read joc first to understand the philosophy and "clojure applied" after that?
18:55TEttingerRedNifre: the only annoyance I have with clojure for small tools is the somewhat long startup time, though there are good ways around that now. I do spend much less time writing the tools though, relative to OOP langs like Java, so that's a benefit :)
18:55TEttingerhttps://github.com/technomancy/leiningen/wiki/Faster
18:56RedNifreTEttinger do you always create jars or do you have very tiny scripts that you run interpreted?
18:56RedNifreRegarding lein, is it a build tool / dependency resolver like all the others (cabal, npm etc.) or does it differ?
18:56TEttingerI almost never create jars unless I have to
18:57TEttingerI run with 'lein run' usually, sometimes 'lein repl' and paste in some snippet
18:57TEttingerfor tiny stuff I just paste it into a lazybot instance I have running
18:58TEttingerlein is a built tool and dep resolver, it doesn't do much too different. it does have good creation of uberjars
18:58RedNifreI like Ruby's shell interop, you can run shell commands just by using backticks: `curl -bla`. How shell friendly is Clojure?
18:58TEttingerit emphasizes cross-platform stuff, and shell commands are not that at all, so...
18:59TEttingerthere is shell support in the standard lib
18:59RedNifreOkay, so it might not be the best choice for glorified bash scripts, huh?
18:59TEttingerhttp://clojuredocs.org/clojure.java.shell/sh
18:59TEttingermaybe. that's largely what I use it for, I suppose
19:00justin_smithProcessBuilder is super powerful, but it is also stupidly limited by portability
19:00justin_smitheg. you can't find out the PID of a process you launched
19:02RedNifresh looks good. But what for do you people use Clojure? Do you use it for the tiniest tools or do you write those in bash or a traditional scripting language? Or do you use Clojure for large projects? Something in between?
19:04TEttingerI've been meaning to use it for larger projects, but mostly I currently use Clojure for small things that I want to get working fast
19:04TEttingerclojure is definitely good as projects start to get bigger
19:06TEttingeran example is this spreadsheet data turned into TSV: https://dl.dropboxusercontent.com/u/11914692/input.txt I run a small, messy script on it to convert it to much more usable text https://dl.dropboxusercontent.com/u/11914692/class-formatter.clj and the output is like https://dl.dropboxusercontent.com/u/11914692/classes200-final.txt
19:09RedNifreThe problem sounds like the kind of thing that I solve with Ruby, but the Clojure code looks surprising to me. I'll have to stare at it for a moment...
19:10RedNifreAh, so inp is the file stream and the -> macro funnels it through several processing steps?
19:11TEttingerit was never meant to be read!
19:11TEttingerthis was meant to be written once, clumsily, using regexes to make regexes lol
19:11TEttingerI probably have cleaner scripts
19:11RedNifreheh
19:12RedNifreIndentation would be nice :)
19:12TEttingerthat's just one I've used a bunch and produced very very quickly
19:12TEttingerthat one I just paste into the repl
19:12RedNifreI see.
19:12TEttingerso the indentation doesn't affect it
19:12TEttinger(it wouldn't anyway I guess)
19:13RedNifrePersonally I'm still not used to Lisp's ((()()))()()()))))) but I solved it with this thing called "parinfer": I just use indentation and parinfer just places the parens for me.
19:13TEttingerwhat I pasted is a terrible example of what makes clojure powerful, there'
19:13TEttingerwhat I pasted is a terrible example of what makes clojure powerful, there's a lot better examples I can probably dredge up
19:14RedNifreSure, I only understand it up to "(def fin" so far.
19:14RedNifreDoes "fin" stand for "finishing touches"?
19:15TEttingerhehe yep. I would probably recommend this instead, in retrospect http://ideone.com/L0eHc6
19:15TEttingerh.p.lovecraft-style rambling generator
19:15RedNifreweird, the syntax highlighting is almost completely pink.
19:16TEttingerthat can technically be compressed down to one IRC message, about 400 chars. I won't paste it since it's super illegible that compressed
19:16TEttingeryeah ideone is broken with '
19:16TEttingerit thinks ' is a paired quote somehow
19:19TEttingeroutput is below
19:19RedNifreWhat is "#(do["? Wasn't "#(" the beginning of a lambda and doesn't do usually look like (do (bla) (blaa) (bleh))?
19:20justin_smithRedNifre: both of these things are correct
19:20TEttingerthat might have been to produce a vector in a lambda with a little less code
19:20justin_smithRedNifre: #([...]) will error when called, because it calls a vector with no args
19:20TEttinger,(map #(do [% %]) [1 2 3])
19:20clojurebot([1 1] [2 2] [3 3])
19:21justin_smith,([:a :b :c] 1)
19:21clojurebot:b
19:22RedNifreI don't understand why #(do [%]) should be fine but #([%]) isn't. To me, both look like the lambda would just return the vector with the parameter inside.
19:22TEttingeranother repacement would be
19:22TEttinger,(map #(vector % %) [1 2 3])
19:22justin_smithRedNifre: try expanding
19:22clojurebot([1 1] [2 2] [3 3])
19:22justin_smith,'#([:a])
19:22clojurebot(fn* [] ([:a]))
19:23justin_smithRedNifre: see the problem?
19:23justin_smith,'#(do [:a])
19:23clojurebot(fn* [] (do [:a]))
19:24TEttingerunless there's a quote preventing it from being run, parentheses in clojure go before fn or macro calls. vectors and maps actually can be used as fns, but they need an index or key as an argument to that fn
19:24justin_smith[] is callable, if #([]) was not an error, and returned [], then #(println) would return the println function, instead of calling it
19:25RedNifreOh, that makes sense.
19:25TEttingerI think the do[ was a relic from when I ported it from the one-liner
19:25RedNifreThat also means that if I actually want a lambda that returns the println function I have to write (fn [] println) instead? Or maybe #('println) ?
19:26justin_smithRedNifre: 'println is a symbol
19:26justin_smithnot a function
19:26justin_smith,('println "hello" "world")
19:26clojurebot"world"
19:26justin_smithsorry, that was evil
19:26RedNifreMy bad, I confused the quote with "don't execute it yet".
19:26justin_smithRedNifre: with symbols it means "don't resolve it yet"
19:27TEttinger,(constantly println) ; this is a nice way to return a fn that when called will return the value you want, every time
19:27clojurebot#object[clojure.core$constantly$fn__4614 0x7e9f909b "clojure.core$constantly$fn__4614@7e9f909b"]
19:27justin_smith,((resolve 'println) "hello" "world")
19:27clojurebothello world\n
19:27TEttinger,(map (constantly 11) [1 2 3])
19:27clojurebot(11 11 11)
19:27RedNifreWhy did clojurebot just say "world"?
19:28justin_smith,('a 'b 'c)
19:28clojurebotc
19:28TEttingerI don't know either, haha
19:28justin_smith,(get 'a 'b 'c)
19:28clojurebotc
19:28justin_smitherr
19:28justin_smith,(get 'b 'a 'c) ; this is actually equivalent
19:28clojurebotc
19:28RedNifrewell, I don't understand that one either.
19:28justin_smithRedNifre: when a symbol is called, it acts as get of itself
19:28justin_smith,('a '{a 0})
19:28clojurebot0
19:28TEttingerjustin_smith: is that the default get thing?
19:28justin_smith,('a '{b 0} 'c)
19:29clojurebotc
19:29justin_smithTEttinger: yup
19:29justin_smithRedNifre: here's an amazing bug
19:29justin_smith,('or nil false)
19:29clojurebotfalse
19:29justin_smith,('or true false)
19:29clojurebotfalse
19:29justin_smithhaha
19:29justin_smith(bug being using 'or instead of or of course)
19:29TEttinger,(get {:a 1} :a)
19:29clojurebot1
19:30TEttinger,(get {:b 1} :a)
19:30clojurebotnil
19:30TEttinger,(get {:b 1} :a :not-found)
19:30clojurebot:not-found
19:30TEttingerdoes that make it a bit clearer?
19:30RedNifreI only know why (:a {a 0}) would be 0, I don't understand what happens in ('a '{a 0}). How does clojurebot execute quoted forms?
19:30justin_smithRedNifre: you don't get quote
19:31TEttingerto be honest I don't either :)
19:31justin_smith'{a 0} is the same as {'a 0}
19:31justin_smithsince 0 is self-evaluating
19:31justin_smithfor that matter, '{:a 0} is the same as {:a 0} because all parts of the form are self-evaluating
19:32RedNifreOkay, I only understood quote as "Don't run this code" and that I can run it later with eval which I shouldn't.
19:32justin_smithquoting prevents lists from evaluating, and it prevents symbols from being resolved
19:32justin_smithRedNifre: no, it is not "don't run this code" it's "don't execute lists (just leave them as lists) and don't resolve symbols (just leave them as symbols)"
19:32TEttingerwhere something like (a b c) is a list of symbols, and unless quoted, would try to resolve them
19:33TEttinger,(a b c) ; will fail
19:33clojurebot#error {\n :cause "Unable to resolve symbol: a in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: a in this context"\n ...
19:33TEttinger,'(a b c) ; will not fail
19:33clojurebot(a b c)
19:33TEttinger,'(a b) ; will not fail
19:33clojurebot(a b)
19:33justin_smithRedNifre: now it does turn out that eval uses lists and symbols, but we have reader macros, which means that certain things still happen, even inside quoted data - eg '{} still constructs a hash-map because that's part of reading not eval
19:34RedNifreSo '(+ 1 2) is a list containing +,1,2, right? What exactly is '+? I guess '+ is not the function yet, it's just ... the symbol... but what does that mean? Does it sort of mean it's something like a String containing the character "+" and resolving the symbol will find the + function? Or is the symbol a more technical thing like the memory location of the function or something?
19:34TEttinger,('a 'b) ; but this doesn't quote the list, so it's trying to call the quoted symbol 'a now
19:34clojurebotnil
19:34justin_smithRedNifre: symbols are like keywords, but they also resolve to vars in a namespace
19:35TEttinger,`+
19:35clojurebotclojure.core/+
19:35justin_smithand also to locals inside a bound body
19:35TEttinger+ actually knows what its namespace is, I think, which is how ` (backtick, aka syntax-quote) can get the namespaced fn name
19:36justin_smithTEttinger: '+ has no namespace, eval decides what the namespace is based on the mappings in the current context
19:36TEttingerohh
19:36justin_smithTEttinger: for example what if it's bound to a local? then it has no namespace
19:36TEttingermm
19:36justin_smithwhat if you used :refer-clojure [:exclusions [+]] or however that works
19:36RedNifreSo if I define my own + in my own namespace and then do '+ I'll get a symbol for my own + and even if I throw this '+ over to another namespace it will there not mean the standard clojure +, it will still mean my own + from the other namespace?
19:37TEttingerso '+ doesn't know, the environment produced from things like require is what knows
19:37RedNifreah, so the opposite of what I said.
19:37justin_smithRedNifre: '+ isn't even "for" anything yet - you prevented the resolving step
19:37justin_smithif you used + it would resolve to the one in the same namespace, sure
19:37justin_smithRedNifre: for the last part, no, absolutely not
19:37justin_smithsymbols know nothing
19:38RedNifreSo '+ is more like the String containing the character plus?
19:38justin_smithnamespaces decide what symbols mean
19:38justin_smithkind of, yeah, with some special behaviors that strings dont' have, of course
19:38TEttingerI think the last statement is closest yea
19:39TEttingerit does seem like you're picking this up pretty quickly, RedNifre
19:39TEttingerthe quote thing can get kinda complex at first
19:39justin_smithRedNifre: maybe it would help to mention that a namespace owns a hash-map, and the keys are symbols, the values are vars, and vars are dereffed to get values created with def
19:39RedNifreRight, so when the symbol gets resolved, Clojure checks the current namespace for a function or variable that kinda has the same String name like what's in the symbol.
19:39RedNifreSo quoted symbols can lead to disasters when using code obfuscation?
19:39justin_smithRedNifre: and when you call def, you are mutating the hash-map to add a new symbol as a key
19:39RedNifreThanks, TEttinger.
19:42RedNifreOkay, now I'll ponder about "'{a 0} is the same as {'a 0}" for a moment...
19:42justin_smith,(= '0 0)
19:42clojurebottrue
19:43justin_smith,(= '{} {})
19:43clojurebottrue
19:43justin_smith,(= ':a :a)
19:43clojurebottrue
19:43RedNifreSee, to me it looks like '{a 0} is a symbol and {'a 0} is a map that maps the symbol 'a to 0. I also don't understand what the hint "0 evaluates to self" means.
19:43justin_smithit's what I was saying about the reading step
19:43justin_smiththe reading step happens before resolve, and resolve happens as the first step of eval
19:43justin_smith' does not prevent reading - "" prevents reading
19:44RedNifreAre '0 and 0 really the same or does = turn the '0 into 0 before comparing?
19:44justin_smithRedNifre: '0 is 0
19:44justin_smiththe reader creates 0
19:44justin_smithit has nothing to do with eval
19:44justin_smithreading has to happen before ' can be applied
19:44justin_smithactually, reading turns 'x into (quote x)
19:44justin_smith,''x
19:45clojurebot(quote x)
19:45RedNifreAnd (quote 0) is 0?
19:45justin_smithwill, the one above is the list '(quote 0)
19:45justin_smithbut yes
19:45justin_smith,(quote 0)
19:45clojurebot0
19:45justin_smith,(quote (quote 0))
19:45clojurebot(quote 0)
19:46justin_smith(quote just quoted another quote)
19:46justin_smithbut 0 above is still 0!
19:46RedNifreWhich 0 above?
19:46justin_smithbut of course "0" contains no 0 - that actually prevented reading
19:47RedNifreYou mean the String "0" containing the character with the unicode value 32?
19:47justin_smithRedNifre: the one generated by (quote (quote 0)) is a regular 0 - it is created before the quote is applied
19:47justin_smithRedNifre: yes, "" is what prevents reading
19:47justin_smithonce reading happens, all literals have been created
19:47justin_smiththis includes data structures and numbers and symbols and keywords - all self-evaluating things
19:48justin_smithRedNifre: remember it's a REPL
19:48justin_smithR happens first
19:49RedNifreJust to be sure, are we talking about something that only behaves like this in the REPL or is it the same in regular compiled clojure?
19:49justin_smithRedNifre: most languages have something like this (in the compiler), but lisps have the annoying / cool property that you end up needing to care, because forms are first class in the language.
19:49justin_smithRedNifre: there is no such distinction
19:49justin_smiththe repl is regular compiled clojure in every aspect
19:49justin_smiththere is no compiler / interpreter split
19:50RedNifreIs '0 just syntactic sugar for (quote 0) or is this a change or does it make no difference because resolving syntactic sugar is kinda what other things like macros are doing?
19:50justin_smithRedNifre: yes, ' is synctactic sugar for (quote)
19:50justin_smithjust like @ is syntactic sugar for (deref)
19:51RedNifreDoes Clojure even have a distinction between syntactic sugar and macros/reader stuff?
19:51justin_smithRedNifre: we have the reader itself (for things like ' and data structures and @), reader macros (all things that start with # are reader-macros), then macros, and then finally functions to evaluate
19:52justin_smithI might have missed something there, but I think that's most of it
19:52RedNifreOkay, so there is a hierarchy and '0 meaning (quote 0) is more language featurey than the macros I can define myself...
19:53justin_smithyes
19:54RedNifreSo I take it that when I write (= '0 0) what happens is that it first turns into (= (quote 0) 0). I assume quote is also a macro which resolves it to (= 0 0). That is the final code that gets compiled and when it gets run it evaluates to true?
19:58justin_smithRedNifre: well, it resolves to true at compilation time
19:58justin_smithso no byte code is generated - it just returns true
19:58RedNifreBut that's just an arbitrary optimization, right?
19:58justin_smithso yeah, you have the idea
19:58justin_smithRedNifre: sure, yeah, but it would be a silly one to leave out
19:58RedNifreFair point.
19:59justin_smithRedNifre: and it's a gotcha - people expect the clojure compiler to emit byte code for things that have top level side effects, but instead the side effects are invoked while compiling
19:59justin_smithcommon newcomer pitfall
19:59RedNifrehuh?
19:59RedNifreTHat sounds surprising.
19:59justin_smithRedNifre: (def war (launch-the missiles))
19:59justin_smiththat launches the missiles in order to compile the def form
20:00justin_smithRedNifre: the lesson here is don't ever do top level side effects, unless you are trying to do things at compilation time explicitly
20:00RedNifreThe code looks wrong, it should be (defn war [] (launch-the-missiles)), right?
20:01justin_smithright
20:01justin_smithRedNifre: but it's usually (def connection (connect-to db))
20:01justin_smithworks great in a repl!
20:01justin_smithworks at dev time if you just run the project
20:01RedNifreI have to think about what I would expect (def war (launch)) to do actually.
20:01justin_smithworks poorly when compiling ahead of time to make a jar that java can invoke
20:02RedNifreOkay, well, Haskell would launch the missiles lazily when you try to print the value of the war variable... hm...
20:02justin_smithheh, yeah
20:03RedNifreClojure uses eager evaluation so I would actually expect the missiles to launch when the jar gets loaded into the JVM, not at compile time. Hm...
20:03justin_smithit launches at the time you are creating the jar
20:03justin_smithunless you are doing a non-aot packaging
20:03RedNifreSo compiling evil source code can format my hard drive?
20:06RedNifreIt seems like this makes compilation quite complicated. I'm surprised that parts of the program can run before other parts are even compiled. I guess it compiles the easy parts first and invokes the tricky parts last?
20:06RedNifreHang on, does that mean that compiling a throw away script will run at compile time and the jar will only contain one large print statement with the result?
20:07justin_smithRedNifre: the compiler can be made to execute arbitrary code, this is the premise of a lisp
20:07justin_smithdef is just a trivial example of this, but it goes much deeper
20:07RedNifre:)
20:07RedNifreIt's getting more and more interesting.
20:08RedNifreThat's exactly the stuff I was looking for: strange concepts I'm not familiar with yet.
20:08justin_smithRedNifre: you could easily test what it does in a project with a top level println in the same ns as -main with a freshly created app
20:09RedNifreDoes the joc book cover all this?
20:09justin_smithyes, and probably makes a more coherent explanation of how these things all fit together and why
20:10RedNifreI'm sold, I'll order the book and come back when I have less basic questions to ask :)
20:11RedNifreThank you two for taking the time to clear up my questions. It changed my view.
20:12RedNifreHave a good night!
20:12justin_smithyou too
20:25justin_smithTEttinger: https://twitter.com/voxel/status/586452796125265921
20:28rhg135Heh, any you say?
20:30justin_smith"
20:30justin_smitherr
20:31justin_smith"this is , but we call him bom"
20:33rhg135I think I knew a guy called bom
20:34rhg135The school's IT system must have had fun
20:35blockzombielol
20:38TEttinger@voxel @buzzert I noticed "a baby" is not on that list.
21:08rhg135Whoa
21:16gilchCan anybody explain where "#=" is documented? It's ungoogleable.
21:16blockzombielol
21:16blockzombieit's on the cheat sheet
21:16blockzombie... getting
21:17blockzombiehttp://clojure.org/api/cheatsheet
21:17gilchI don't see it on grimore
21:17justin_smithgilch: it's a reader macro, and is covered in the part of the clojure.org docs about reader macros. Everything that starts with # is a reader macro.
21:17blockzombieah it's not there sorry
21:19justin_smithgilch: oh, wow, it's missing here too http://clojure.org/reference/reader
21:19gilchjustin_smith: you mean http://clojure.org/reference/reader ? The string "#+" not found on page :(
21:20gilch*"#="
21:20justin_smith,(read-string "#=(+ 1 1)")
21:20clojurebot#error {\n :cause "EvalReader not allowed when *read-eval* is false."\n :via\n [{:type java.lang.RuntimeException\n :message "EvalReader not allowed when *read-eval* is false."\n :at [clojure.lang.Util runtimeException "Util.java" 221]}]\n :trace\n [[clojure.lang.Util runtimeException "Util.java" 221]\n [clojure.lang.LispReader$EvalReader invoke "LispReader.java" 1100]\n [clojure.lang.LispRe...
21:20justin_smithanyway, that's what that is - in your repl the above returns 2
21:20justin_smithit's for evaluating arbitrary code at read time
21:20justin_smithit's kind of a terrible feature actually
21:21gilchOh, like common lisp
21:21gilch#.
21:22gilchIt seriously isn't documented anywhere?
21:22justin_smithsorry to mislead, I was sure it would be described with the other reader dispatch in the section on the reader
21:23justin_smithit has to be documented, I'm just wondering where...
21:23justin_smithgilch: this isn't searchable for obvious reasons, but it's described here https://clojuredocs.org/clojure.core/*read-eval*
21:24justin_smithgilch: aha!
21:24justin_smithgilch: in your repl, try (find-doc "#=")
21:25justin_smiththat's clojure.repl/find-doc, but most repls auto-use clojure.repl for obvious reasons
21:27amalloyi think the reason it's not mentione with the reader macros is it's one you're not supposed to use as a feature; rather it's really just for the runtime's internal use
21:29gilchHow am I supposed to tell what's API and what's implementation detail?
21:29gilch*read-eval* is documented
21:30gilchI wonder if I'm missing any other dispatches not on the cheatsheet?
21:31gilchIs there a list of the builtin edn tags somewhere?
21:32justin_smith#= is not an edn tag - the main difference between core/read and edn/read is that it does not respect that flag
21:32gilchSo edn will work on all the other #x
21:32justin_smiththat I know of, yeah
21:33gilch#@? / #?
21:33justin_smithone moment, testing
21:33gilchI can't think of a use edn would have for that
21:34justin_smithoh, just now I tested it, and #? failed
21:34justin_smithso yeah, good instinct on that one
21:35amalloy,(require 'clojure.edn)
21:35clojurebotnil
21:35amalloy,(clojure.edn/read-string "#_1 2")
21:35clojurebot2
21:36gilchI saw #inst and #uuid on the github spec. I thought I saw a #js in code somewhere, but... Maybe find-doc
21:36gilchnope
21:38gilchhttps://github.com/edn-format/edn explicitly says it does support "#_"
21:38justin_smithgilch: also the e stands for extensible, people can add their own readers for # things
21:39gilchbut they have to use namespace/
21:39gilchbut #inst doesn't use namespace/
21:39gilchwhat else doesn't?
21:39gilchjust #uuid so far?
22:21rhg135#= can be useful for derived constants, like if you need a char code but are too lazy
22:23rhg135You can either write a macro, or insert seemingly random numbers
22:33gilchdoes weird things when nested (quote #=(symbol (str foo . bar)))
22:34gilch=>unmatched delimiter?
22:35gilch(quote #= (symbol #=(str foo . bar)))
22:36gilchfoo.bar
22:59rhg135,(str . " what?")
22:59clojurebot#error {\n :cause "Unable to resolve symbol: . in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: . in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: . in this context"\n ...
22:59rhg135I thought so
23:00justin_smith,(str 'foo '. 'bar)
23:00clojurebot"foo.bar"
23:03rhg135Ah
23:05justin_smithhmm
23:05justin_smith,(intern 'sanbox '. "dot")
23:05clojurebot#error {\n :cause "No namespace: sanbox found"\n :via\n [{:type java.lang.Exception\n :message "No namespace: sanbox found"\n :at [clojure.core$the_ns invokeStatic "core.clj" 4032]}]\n :trace\n [[clojure.core$the_ns invokeStatic "core.clj" 4032]\n [clojure.core$intern invokeStatic "core.clj" 6071]\n [clojure.core$intern invoke "core.clj" 6071]\n [sandbox$eval72 invokeStatic "NO_SOURCE_FILE"...
23:05justin_smith,(intern 'sandbox '. "dot")
23:05clojurebot#'sandbox/.
23:05justin_smith,.
23:05clojurebot"dot"
23:05rhg135Box-san!
23:07rhg135Those are a few reasons why I no longer write code after dark
23:07justin_smithoh, wait
23:07justin_smith,(def . "dotty")
23:07clojurebot#'sandbox/.
23:08rhg135,(def . '.)
23:08clojurebot#'sandbox/.
23:08justin_smith,(defn . [] .)
23:08clojurebot#'sandbox/.
23:08justin_smith,(apply . ())
23:08clojurebot#object[sandbox$_DOT_ 0x50807f2e "sandbox$_DOT_@50807f2e"]
23:08justin_smiththat is so weird
23:09rhg135That'd totally mess with elispers
23:09justin_smithseriously
23:09justin_smithI mean it scans really weird even to me as a clojurist
23:12rhg135.s are symbols too!