#clojure logs

2016-02-06

06:40benjyz1hello. I'm wrestling with SQL in Clojure
06:40benjyz1jdbc/insert! for some reason doesn't commit to my database
06:41benjyz1https://www.refheap.com/114533
06:42benjyz1do I need some kind of commit?
06:45benjyz1ok, nevermind, just some weird error
06:46mmeix(makedb) etc is commented out
06:46mmeixah .. ok
09:29thomasfustonAre there recommended ways to build GUI applictions with clojure?
09:46dysfunthomasfuston: if by that you mean 'non-browser applications', it's not recommendable
09:46CaptainLexHehe I was going to say
09:46thomasfustonhmm so its better to have a browserinterface? even to a local app?
09:47dysfunno, it's better to write the app in not-clojure
09:47thomasfustonok, you saying clojure is best for webdevelopement
09:48dysfuni'm saying clojure is ideal for anything where startup time is not a primary requirement
09:48dysfunand that don't require you to write a gui
09:48dysfununless it's a web one
09:49dysfunthe reason for the gui thing is frankly what java offers is shit and because you're on the jvm your interop with C libraries is piss-poor at best
09:51thomasfustonwell i thought i could do a little app in clojure for learning purposes (coming from python), and it should be crossplattform so thought why not clojure
09:51dysfunin practice, if you want a crossplatform gui application, you use qt
09:52dysfuni think the java bindings are pretty outdated last i checked
09:52dysfunand it causes all sorts of deployment issues
09:54dysfunfor the cross platform gui client i've got to build in the next few months, we're being slightly more ambitious, separating all the non-gui stuff out into a c++ library with a c wrapper. you can link that against all OSes including mobile
09:54dysfunof course currently i'm building the web client... in clojure+clojurescript
09:55dysfunthe server, well that's a clojure webservice
09:56dysfunhonestly i'm finding it easier to build for the web than build the clients, significantly so
10:10CaptainLexdysfun: What about using other Clojure targets, like PyClojure? Do those projects still have any momentum?
10:31rhg135I'm building a small gui app in clojure. Clojure starts fast enough and when you need fs io, it's easier and faster than cljs
10:32dysfunCaptainLex: i'm not convinced they're going anywhere
10:33dysfuni've personally got an llvm-clojure project on the back burner
10:33CaptainLexdysfun: True, but for thomasfuston's purposes - building a GUI app just to get his hands dirty - it might be useful.
10:34dysfunor, y'know, he could use python, which is a more suited tool for his purpose and he happens to know
11:18arkhor, y'know, it could be a fun project to learn more clojure
11:19ridcullynever
12:41benjyz1hello. I'm working on a webapp with Clojure and Clojurescript. Ring delivers JSON with middleware, but I can't get the client to read it correctly
12:44benjyz1https://www.refheap.com/114540
12:44justin_smithbenjyz1: the input to the handler won't be js, so js->cljs doesn't help
12:45justin_smithbenjyz1: you need to use js/JSON to turn the string into js data
12:45justin_smithbecause it will just be a string
12:45justin_smith(or you can use whichever cljs wrapper for js/JSON you like of course)
12:54benjyz1thanks. trying with "(js/JSON.parse response)"
12:56justin_smithyeah, that sounds right
12:59benjyz1Unexpected string... when I try to parse {"foo" "bar"}
12:59justin_smithwell that's not valid json
12:59justin_smithare you sending edn format?
12:59justin_smithin that case, you want cljs.reader/read-string or whatever it's called
13:00justin_smithor you could fix your middleware so you actually send json
13:01benjyz1I'm trying (wrap-json-response)
13:02justin_smithOK, are you setting the content-type header?
13:02justin_smithyou might need to make sure your accept header is right on the client side too, I forget
13:06benjyz1I was looking around whether I can find a template which integrates ring and CLJS
13:11macroliciousdoes anyone know which rainbow delimiters mode works well in emacs -nw (in a terminall… iterm2 in my case)?
13:11justin_smithmacrolicious: it should just be a question of adjusting the faces defined by rainbow-delimiters mode right?
13:12macroliciousah ok… too noob to know that… sweet...
13:13justin_smithmacrolicious: M-x customize-group<return>rainbow-delimeters<return>
13:14justin_smiththen from there go to reainbow-delimiters-faces, and edit and preview to hearts content
13:15justin_smithmacrolicious: it's also possible to customize these things outside of the customize interface, but customize is handy especially when new to emacs
13:16macroliciousthat's really helpful… and I'll be able to pick the right faces...
13:47kwladykaWhat do you think about #_ in parameters (defn create-uuid! [uidable-id uidable-type type #_expired-in [n time-unit]]) <- is it good idea or should i use [exprired-in-n expired-in-time-unit] ? What is the standard?
13:48kwladykai think send options is better
13:48kwladyka*second
13:49kwladykamaybe even like that (defn create-uuid! [uidable-id uidable-type type [expired-in_n expired-in_time-unit]]
13:49justin_smithwhy not (defn create-uuid! [uidable-id uidable-type type [n time-unit :as expired-in]] ...)
13:50kwladykait is better, thanks!
13:52djbkdi'm starting Web Dev 2.0 book and can't seem to get through the first example...is ring broken on clj 1.7?
13:52justin_smithdjbkd: the lein-ring plugin is broken with the latest lein
13:53djbkdah ok
13:53justin_smithdjbkd: if you "upgrade" to an older lein that fixes it
13:53djbkdhahaha
13:53djbkdso, like nodejs :c
13:53djbkdhttps://twitter.com/BadKittyDaddy/status/696041540896993280
13:53justin_smithhopefully the next ring will fix this :)
13:53justin_smithdjbkd: sad timing for the new lein breakage, with that great book coming out...
13:54djbkdyeah i really like clj as a language
13:54djbkdbut such is the nature of open source
13:54kwladykaAnybody from Switzerland here? I am wonder how looks Clojure work there.
13:54djbkdi'll try downgrading, thanks
14:02macroliciousjustin_smith: got my delimiters all looking pretty… took a bit to figure out the customization interface, but yay!
14:02RedNifreIf the clojure and leiningen versions in the ubuntu repository are very outdated, should I just extract the clojure zip somewhere and put a link named "clojure" in my ~/bin?
14:03justin_smithRedNifre: you don't need a zip
14:04justin_smithRedNifre: lein is a shell file
14:04RedNifreoh, so if I have lein I'm all set?
14:04justin_smithRedNifre: if you are using lein, lein finds and uses whichever version of clojure your project config tells it to
14:04justin_smithso yeah, if using lein, just the script suffices
14:04RedNifreI don't have a project config yet, I'm starting with clojure right now :)
14:05RedNifreokay, sounds good, I'll see how far I get...
14:05justin_smithRedNifre: though I do like keeping the latest clojure jar around for fiddling (faster startup time / simpler tooling as long as I don't need deps)
14:05justin_smithRedNifre: right, lein has a default clojure it will use, but once you create a project the project needs to declare a clojure version
14:06justin_smithRedNifre: if not using a project and therefore not having any deps, yeah, just use clojure.jar, use rlwrap too that makes it nicer
14:06justin_smithbut pretty early on you will see the value of lein if you decide to use any deps outside clojure itself and the default jvm stuff
14:08RedNifreI have no opinions yet since I'm just starting out. The tutorial introduces lein and since I see the value of cabal/npm/gradle I'll probably like lein anyway.
14:08dysfunlein is my benchmark for build tools now
14:08justin_smithRedNifre: it is much better than the default usage of any of those, but cabal used properly is probably lein's equal :)
14:09dysfunbut noone uses cabal properly, that's why we have stack :)
14:09justin_smith(properly meaning, no sharing of deps implicitly between projects, all things sandboxed but artifacts of same version shared via a cache)
14:09dysfunyou know, you'd probably quite like stack
14:10justin_smithI'm sure, I'm still a n99b at haskell though
14:10justin_smithodometer hasn't even rolled over to n00b yet
14:10dysfunright, well even more reason to use stack. it's the best way to get started these days
14:10justin_smithcool
14:10RedNifrePossible, I heard about it peripherily. I also heard something about some cabal nix crossover thingy, does stack work well with nixOS as well?
14:11dysfunand the truth is that once you grok the syntax, just tweak monads until the type works and stop worrying about it
14:11justin_smithRedNifre: leiningen does with jvm deps something very close to what nix does to OS level deps (isolated subsets that are independent but sharing a cache of immutable versions)
14:11dysfuni'm not a nixos user, but loads of hackage has nixos builds
14:12dysfunbesides, i'm too busy solving problems with haskell to be a haskell programmer
14:13RedNifreUnfortunately I haven't used Haskell in about a year :/
14:14dysfunjustin_smith: https://github.com/jjl/ctaas/blob/master/src/Main.hs 53 lines in memory hashtable webservice
14:14justin_smithanyway, clojure's great, isn't that why we're all here?
14:14RedNifremaybe? :)
14:14dysfunhaskell has a different useful niche
14:15justin_smithback when bytemyapp of "haskell from first principles" fame was a clojure programmer, we actually had to enforce a "no haskell before 7 pm" rule here
14:15RedNifreI'm currently working through various programming languages, Haskell is great but brutal, after that I tried node.js with coffeescript which was bad but highly productive. Now I'm looking at Clojure because it promises to be somewhat as tidy as Haskell, but also as productive as those messy languages.
14:16dysfunah yeah, i pissed him off once by saying "fucking haskell programmers"
14:16justin_smithRedNifre: right, clojure is a great mix of tidy enough to be sane while pliable enough to do things quickly and refine later, imho
14:16dysfunclojure is my preferred tool when it's a good fit
14:17RedNifreThat sounds a bit like a tautology.
14:17justin_smithdysfun: "x is my preferred too when it's a good fit" is a low information statement :)
14:17dysfunnot really. it says "if clojure isn't disqualified, i'll pick it"
14:18RedNifreah, you mean "if it isn't a bad fit"?
14:18justin_smithdysfun: oh, perhaps we understand "a good fit" differently
14:18justin_smithRedNifre: get out of my brain
14:18justin_smithbbl
14:20RedNifredito
14:25RedNifreOh no. What exactly happens when I do "lein run"? How much data does it download?
14:26RedNifreAh dammit. The problem is that my internet connection is broken so I went to a place where there is internet, downloaded lein and a clojure zip and I'm now using my phone's exhausted connection. I guess lein now wants to download several MB of clojure, huh?
14:26mmasticI'm new but I think it would just get your dependencies and whatnot (which could even be the actual compiler). You can always just abort.
14:27RedNifreWell, I just started so I guess it's the compiler. It tried to download clojure 1.8.0, which failed because of networking issues. I have the clojure 1.8.0 zip file though. Can I somehow give that one to lein so it doesn't have to download it by itself?
14:28justin_smithRedNifre: I'd just use "rlwrap java -jar clojure-1.8.0.jar" for now
14:28justin_smithwhen you have a good connection, do the full deal
14:28justin_smith(with lein)
14:28RedNifreHm, it says "if you are behind a proxy try setting the http environment variable". This might be the case because of my cellular provider. How do I set this variable and to what?
14:28kwladykais any reason why "contains?" work only with one key...?
14:29RedNifrejustin_smith what does that command do exactly?
14:29justin_smithRedNifre: starts a clojure repl
14:30justin_smithno other things available except the extensive libs offered by the vm itself
14:30justin_smithit's enough for a start, once you need deps, lein handles those nicely, but why fight to make lein work when your net is crap anyway?
14:30lodin-kwladyka: Huh?
14:31justin_smithlodin-: kwladyka wants (contains? m k1 k2 k3)
14:31justin_smithwhich doesn't work of course
14:31kwladykalodin- exactly like justin_smith said
14:31lodin-And what would be true if m contained all keys?
14:31justin_smithI don't know why, I agree varargs would be nice
14:31amalloyjustin_smith: i think varargs there would be bad
14:32lodin-s/what/that/
14:32amalloybecause there are two reasonable meanings: (every? #(contains? m %) ks), or (some #(contains? m %) ks)
14:32lodin-Precisely, what amalloy said.
14:32justin_smithamalloy: I hadn't considered some being expected
14:33noncom|2is anyone aware of a simple way to align a dava/joda time by 15 min-intervals? i.e. i want any arbitrary number of minutes to align to the nearest upper 15-minute quant?
14:33noncom|2*java/joda
14:33RedNifre(if (contains? food :peanuts :seafish) (dont-eat food))
14:35dysfunobviously that's a too few parameters to if exception waiting to happen
14:36lodin-dysfun: Being sarcastic?
14:37dysfunwell yes, but it is.
14:37RedNifrehow so?
14:37amalloydysfun: it's not
14:37amalloy,(if true 1)
14:37clojurebot1
14:38dysfunmaybe it's just clojurescript that complains
14:38justin_smithdysfun: no, cljs doesn't complain
14:38justin_smithdysfun: maybe you are thinking of haskell
14:39RedNifre:D
14:39dysfuni'm really not. i've just spent two days fixing clojure to work under cljs
14:39RedNifre,(if false 1)
14:39clojurebotnil
14:39lodin-dysfun: Not that I would complain if it complained. The opposite, actually.
14:39justin_smithdysfun: I use single branch if all over my cljs code. This was a point of contention with another def (he didn't believe in ever using when), so I assure you cljs takes this without complaint.
14:40justin_smith*another dev
14:40dysfunwell i can't explain the error messages i've received then
14:40justin_smithif he was a def I could have prevented him from going out of scope, but now we have to hire a guy
14:40justin_smithdysfun: perhaps it was too many args to if
14:40dysfunah yeah, could be
14:40RedNifreWhat's a def and how does single branch if relate to not using when?
14:41justin_smithRedNifre: haha, I typod def for dev, as in coworker
14:41dysfunwell a single branch if would act as a when, so the idea is not needed when
14:41RedNifreah, missed the correction, now it makes sense :)
14:41justin_smithRedNifre: (when p? (f)) is the same as (if p? (f)), when is only different when it has more than one form
14:41justin_smithRedNifre: and my ex coworker hated when
14:42dysfuni quite like when
14:42justin_smithand would use single branch if instead, we argued about it
14:43justin_smithmy argument for replacing single-branch if with when is that if I read when, I know I don't have to scan for a second form - I know all forms are used together if any are
14:43justin_smithso it's a reading comprehension gain
14:43dysfunagreed
14:43RedNifreI don't know enough about when to have an opinion on this yet. :)
14:44dysfunthe truth is life is too short to really care
14:44justin_smiththe opposing side is that "when is only for side effects since it accepts multiple forms" - I'll acknowledge reasonable devs can disagree on this, but the other side is wrong
14:44RedNifrehorray, lein downloaded 1.8.0 and executed my example lein project and it outputted "Hello world!".
14:44justin_smithnice
14:45dysfunyeah, that's a good strategy for many tools
14:45mmasticIs there perhaps anyone here that came from Haskell?
14:46dysfuni came back to clojure after taking some time out to do haskell
14:46justin_smithRedNifre: once I had an error with some new deps while working in a cafe, so I deleted my m2 cache (where lein keeps all your deps) and tried to reset things. I have since learned that deleting the m2 cache is never actually needed except for the exact case I created then: the wifi in the cafe was giving me a small html file containing a click to agree and use the internet form instead of the jar files I was attempting to download
14:47RedNifremmastic yes, me, sort of.
14:47mmasticOh, I have and I'm trying to understand how API works here, especially with dynamic typing. Do you not check for types at all? I don't imagine it's idiomatic to assert the type of every single argument, right?
14:47dysfunjustin_smith: well it would have failed its checksum then wouldn't it?
14:47justin_smiththe result of this was a lot of things with names like "clojure.jar" and "ring-plugin.jar" etc. which all contained the same stupid snippet of html instead of clojure code :P
14:47justin_smithdysfun: hell, without a pom how would I get a checksum? the pom files contained html too
14:47dysfunmmastic: you tend to worry more about the shape of things than their type
14:48dysfunright, but it's never going to find the checksum matches, is it?
14:48RedNifremmastic no idea, I'm on the first page of a clojure tutorial here.
14:48justin_smithmmastic: in practice we care much more about protocols and interfaces and multimethods. If something implements the right protocol or multimethod, the code should work
14:48justin_smithmmastic: usually this is implicit because we are using code whose primitives are all defined in terms of thse protocols and multimethods
14:49RedNifreWhich brings me to REPL colors: The "brave" tutorial shows lein repl with some fancy colors which I don't see for some reason. Is there an easy fix (I probably don't need repl colors that badly but I wouldn't dismiss them if they were easy to enable).
14:49justin_smithbut sometimes you get low level enough to need to define your own protocols / multimethods / interfaces, or extend them
14:49mmasticOh I see, but is it idiomatic to use protocols and such? I figured it's preferred to keep it Lisp-y and only use protocols for Java interops.
14:49dysfunjustin_smith: is that low level?
14:49justin_smithRedNifre: I am unaware of any actual repl color feature outside of maybe editor integration
14:50justin_smithmmastic: lists are a protocol
14:50justin_smithetc.
14:50mmasticdysfun: Are you referring to the collection abstractions?
14:50dysfunmmastic: protocols are useful for mimicking existing behaviour
14:50justin_smithmmastic: so it's lispy by using protocols :)
14:50dysfunyes
14:50RedNifrehm, maybe the tutorial just enabled syntax highlighting for every piece of clojure code which accidentally colored the repl listings there.
14:50dysfunit's basedo n what justin_smith is saying
14:51RedNifreWhy is it called "-main" and not "main" or something like that?
14:51mmasticYeah but it's not Lispy to define protocols for your data, right? it's all about maps, is that correct?
14:51justin_smithmmastic: the protocls and multimethods that most of clojure.core uses are extended very pervasively - you can get a seq from a string, an array, a list, a vector, a hash-map, ....
14:52justin_smithmmastic: so you don't need to type-check something you need a seq from - though seq will throw an error if it can't make a seq from the arg
14:52dysfunRedNifre: because main() is the java function. when you write :gen-class, it writes a wrapper main() function which sets up clojure and calls -main
14:52FiredBall-0x71join ##astara prince
14:52FiredBall-0x71http://www.pearltrees.com/pvpeliter/laptop-disini-bought-governor/id15409744#item167481741, , xWindow 10 ENTERPRISE , FREE CLASSIFIED OS FROM THE MOST HIGH HAS BEEN RELEASED , CLICK ON THE LINK THAT POP UP AND CLICK DOWNLOAD ... . DON'T FORGET TO JOIN ##Astara ... .
14:52RedNifredysfun I see, thanks.
14:52justin_smithmmastic: lispy is that the only data structure you have is a list
14:52lodin-mmastic: I disagree with that. For pure containers, sure, no need to not to use a map, but for other values where you have invariants and such that you need to maintains I suggest defining your own interface (which may use a protocol).
14:52justin_smithmmastic: clojure extends that to "everything implements seq" (within reason)
14:52justin_smithvia seq, we can treat everything as a list if needed
14:53dysfunwhen we say lispy in clojure, i think we mean more 'makes good use of builtins'
14:53justin_smithmmastic: and maps and lists are protocols, in clojure
14:53justin_smithso it's a false dichotomy
14:53dysfun"doesn't reinvent the wheel" perhaps
14:54dysfunor "knows when to reinvent the wheel" :)
14:54justin_smithmmastic: another way to put it is that in practice "everything is a list" and "every collection implements the protocol for lists" are pretty much the same when coding
14:55mmasticAh I see. I'm pretty torn, I had figured they say that in Lisp/Clojure API is data and mean that. So if I have to enforce an invariant, map isn't a good choice anymore?
14:55dysfunyeah, for example you can treat a map as a list, it contains a vector of [key value]
14:55RedNifreNot sure if this is interesting to you clojure pros here, but I discovered this "parinfer" atom editor plugin which places parens based on indentation, which really helps people like me who aren't used to all these parens yet.
14:55RedNifreBasically, you indent the code like in python or haskell and the parens appear by themselves.
14:56justin_smithdysfun: mmastic: and that map -> ([k v] [k v]) transition maps directly to the idiom of alists in lisp
14:56lodin-mmastic: You can use a map, but you should probably not access the map directly, since the actual data representation may change. So provide functions to get the data that you want from it.
14:56justin_smithRedNifre: I look forward to using it when it's mature maybe, it looks like a cool concept
14:56lodin-mmastic: I can clarify that I think this mostly applies when you cross library boundaries.
14:56justin_smithlodin-: well, even "map" is a protocl, not a concrete data type
14:57mmasticAnd I assume a constructor function as-well, yeah?
14:57justin_smithmmastic: ?
14:57RedNifreCan anybody comment on emacs vs atom editor? I encountered atom first, but both editors seem to implement the same concept (powerful texteditor that you can customize with a simple language).
14:58mmasticjustin_smith: Yup, I believe this is the case, however by map I just mean this kind of data-structure of pairs.
14:58justin_smithsure, right, and that's what that protocol means too
14:58dysfunif you like lisp, you'll like emacs.
14:59dysfunbut the real advantage of emacs is that it's very fast to edit text when you've learned certain shortcuts
14:59dysfunand basically unusuable until you've learned the basics
15:01mmasticThanks a lot for your help everyone; It's immensely appreciated.
15:01RedNifreAh, so I reached the "when" part of the tutorial and unlike in my imagination, it is NOT like a switch statement; it's actually an else-less if, right?
15:01justin_smithright, and it accepts any number of forms
15:01RedNifreIf "when" is an else-less if, why is the "else" part of an "if" optional?
15:01justin_smithso that must clarify the above quite a bit
15:02justin_smithRedNifre: "any number of forms"
15:02dysfun(when (foo) (bar)) ; returns result of (bar)
15:02justin_smith(when p? (fire missiles) (issue apology to mother) (say goodbye) (exit))
15:02justin_smitheach action is done in turn - wouldn't work in an if
15:02RedNifreYeah, I think I understand that. I don't understand what you want to tell me by "any number of forms".
15:02dysfun(when (foo) (bar) (baz)) ; calls bar, then baz, returns (baz)
15:03justin_smithRedNifre: (f) is a form
15:03RedNifreYes, I think I understand. And I could do (if bla (do a b c)), right?
15:03justin_smithsure, and that's what when is
15:03justin_smithwhen just looks nicer
15:03RedNifreOkay, I guess I agree with you then that when is nicer than an else-less if. But I don't understand why an else-less if is even allowed.
15:03dysfunthese "not strictly necessary" things actually make clojure quite nice
15:04RedNifreHm, I guess you can just comment out the "else" part, huh?
15:04RedNifre...without rewriting it to a "when"...
15:04justin_smithRedNifre: no need for a comment...
15:04justin_smith,(if true 1)
15:04clojurebot1
15:05justin_smith,(if false 1)
15:05clojurebotnil
15:05RedNifreNo, I meant if you had (if bla (println "fine") (println "not fine")) and you quickly wanted to change it to not print "not fine" then you could comment out that line without being forced to rewrite it to a "when".
15:05justin_smithI mean, I guess, sure
15:05dysfunnot if you use a line-comment like most people, because the parens need to match
15:06RedNifreah, right, I had java style parens in mind.
15:06RedNifreso when to use an else-less if?
15:06dysfunyou could use #_ though
15:06justin_smith,(#_#_#_#_#_#_#_#_#_ we have better things than end of line comments)
15:06clojurebot()
15:06dysfunlol
15:06dysfunpersonally i won't be using the else-less if now i know about it
15:06justin_smithplease don't use #_ like that, with the sole exception of commenting a matching binding/value pair in let or a hash map with #_#_
15:07RedNifre,(#_ 1 2)
15:07clojurebot#error {\n :cause "java.lang.Long cannot be cast to clojure.lang.IFn"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.Long cannot be cast to clojure.lang.IFn"\n :at [sandbox$eval97 invokeStatic "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval97 invokeStatic "NO_SOURCE_FILE" 0]\n [sandbox$eval97 invoke "NO_SOURCE_FILE" -1]\n [clojure.lang.Compiler eval "Compiler.java" 6927]...
15:07justin_smithRedNifre: that expands to (2)
15:07RedNifrethanks.
15:07justin_smith,(#_#_ 1 2)
15:07clojurebot()
15:07justin_smithmy chain of #_ was perhaps less random than it looked
15:08dysfundo you like showing off in front of newbs?
15:08RedNifrehow does that work exactly?
15:08justin_smithRedNifre: #_ eats exactly one form
15:08justin_smithRedNifre: so N #_ eats N forms
15:08kwladyka"Boot is a build tool. That said it's task composition features only get to shine when multiple build steps are involved." <- is it not job for Continuous Integration or another tool? I mean shouldn't it be separated for lein + tool to deploy?
15:08RedNifrewhy can you type them without spaces between them?
15:08justin_smithkwladyka: boot is a replacement for lein
15:09dysfunRedNifre: because the reader is special
15:09justin_smithRedNifre: they are reader macros, they don't obey the rules regular symbols do
15:09justin_smithRedNifre: another way to put it is for the same reason you can interchange [ [ ] ] with [[]]
15:10RedNifreCan you change as many as you want or are they defined separately, i.e. #_ and #_#_ and #_#_#_ up to, say 20 or something?
15:10justin_smithboth are using the readers lowest level rules about where forms begin and end
15:10RedNifre*chain, not change
15:10dysfunin theory, they're not limited. in practice, who knows?
15:10dysfundon't overuse them
15:10justin_smithRedNifre: there might be some stack overflow issue, I really shouldn't have even showed that silly #_#_#_#_#_ trick
15:11dysfunjustin_smith: on a pushbackreader?
15:11RedNifre"same reason .. [[]]" I thought I can type [[]] because in clojure, square brackets work just like normal parens (unlike in other lisps where there are only regular parens)
15:11justin_smithRedNifre: same reason ( ( f ) ) is the same as ((f))
15:11justin_smithRedNifre: these are all reader rules
15:11dysfunor because there are special rules for interpreting parens and square barackets
15:12RedNifrehm, I'll ignore #_ for now...
15:12justin_smithRedNifre: what I mean is that #_ being special is on the same level as () or [] or {} being special, none of these need spaces for parsing
15:12dysfunwhen we say lisp has 'no syntax', we mean it has as little as we can get away with
15:12justin_smithexactly
15:13RedNifreHeh, I actually CAN comment the whole "else" line in an "if" because parinfer fixes the missing paren.
15:13dysfunnice
15:13justin_smithwell there you go
15:13justin_smithbut #_ can be more elegant sometimes
15:13dysfunand it works in all editors
15:14RedNifrealright
15:14justin_smithI am going to go to the office and try to catch up on my day job where I write clojure now. Yay!
15:14dysfunalso use sparingly
15:15RedNifreNow the tutorial introduced the "=" operator but didn't say much about it. Is it as strange as in Java (don't compare Strings that way! Integer autoboxing doesn't happen but it works for the first 127 Integers anyway!) or is it more like calling the "equals" method?
15:15justin_smithRedNifre: we don't have operators
15:15justin_smith= is a function
15:16justin_smithand it's more like the equals method
15:16RedNifreokay
15:16justin_smith,(= () [])
15:16RedNifreso it's sane and I don't have to learn any special rules, huh?
15:16clojurebottrue
15:16justin_smithRedNifre: is the above sane?
15:16justin_smithdepending on your opinion of that, it may or may not be sane
15:16justin_smith,(= 1.0 1)
15:16clojurebotfalse
15:17RedNifrehey!
15:17RedNifreWell, (= () []) to me would be undefined behaviour since I'm comparing two things with different type so I don't worry about it... on the other hand...
15:17RedNifrehmmmm...
15:17dysfunwe say clojure data have value semantics - we always compare their values, not their references
15:17justin_smithstructural equility for immutable things is pretty nice I think
15:18justin_smithdysfun: but haskell has that too, but it still wouldn't call two different types equal
15:18justin_smithwhich is where structural equality comes into play
15:18justin_smithstructural equality is kind of cool but also weird but also useful
15:19RedNifrewell, Haskell would compile (= 1.0 1) as (= 1.0 1.0) since the first number is obviously float so the second one must be float as well, otherwise you wouldn't compare the same type. Go won't compile it because you try to compare different types (no overloaded number literals there). Java would compare the numbers I think?
15:19justin_smithI still find (= () []) and (not= 1 1.0) a quirky combo of behaviors :)
15:20kwladykajustin_smith replacement? More like another tool not replacement?
15:20dysfuni quite like 'shape typing'
15:20RedNifreWhat's the justification for (= 1 1.0) being false?
15:20justin_smithkwladyka: boot is meant to replace lein - you can use one or the other, there's rarely need to use both, ideally never need to use both
15:20dysfunwell for a start, floats are approximations of numbers :)
15:20RedNifrebut in this case it approximates 1 perfectly.
15:21neoncont_justin_smith: is (= ["structural equality" "isomorphism"])?
15:21justin_smithRedNifre: for another potentially confusing detail, we have == for numeric value equality that ignores type
15:21kwladykajustin_smith just not sure about idea of boot. Is not better to have lein + CI instead of boot?
15:21kwladykai didn't use boot so i don't know details
15:21dysfunkwladyka: boot is like lein, but different
15:21justin_smith,(== 1 1.0 3/3)
15:21clojurebottrue
15:21dysfunsince i started porting my stuff to support clojurescript, i find boot a better fit
15:22RedNifreokay, but can I use == on other things?
15:22justin_smithkwladyka: boot starts faster, has a cleaner implementation, and is imperative instead of declarative. Some people like these things.
15:22dysfunit doesn't start faster here
15:22justin_smithRedNifre: no, only Number instances
15:22justin_smithdysfun: perhaps I was misled
15:22kwladykadysfun can you give more details why?
15:22RedNifreIf (= 1 1.0) is false and (== 1 1.0) is true I would expect (= () []) to be false and (== () []) to be true.
15:22dysfunthey're both slow here
15:23justin_smithRedNifre: that would be consistent but sadly is not the case
15:23dysfunkwladyka: because i get to have one watcher to update everything
15:24kwladykadysfun watcher?
15:24dysfunfor instance i have a task that watches for updates and then runs the clojure tests and then the clojurescript ones
15:24justin_smithRedNifre: I think the idea is that turning '(a b c) into '[a b c] loses no information, no matter what a b and c are
15:24justin_smithRedNifre: you can't say the same about number types
15:24dysfuna watcher is simply a builtin boot facility that watches for file changes
15:24RedNifreWell, I'm new to Clojure so I might not have the right perspective here but right now those seem like the worst equality rules I have ever seen (aside from javascript's 1 == "1")
15:24kwladykadysfun and that is the point. Isn't it job for CI software like teamcity ?
15:24kwladykadysfun oh in that way
15:24dysfunRedNifre: they're not a bad set really, but always ask what you want
15:25kwladykadysfun if i know lein can do the same with cljs
15:25dysfunkwladyka: no, boot is like leiningen
15:25dysfunyou do want to run your tests before you push them don't you?
15:25justin_smithRedNifre: as was discussed above with mmastic, we don't really care about types most of the time, we care about protocols. Structural equality works for structures that implement the right protocols to be compared as equivalent.
15:25justin_smithRedNifre: also, = works between numeric subtypes that agree on the exact / lossy divide
15:25justin_smith,(= 1 3/3)
15:25clojurebottrue
15:25justin_smith,(= 1 1N)
15:25clojurebottrue
15:25RedNifrewat
15:26justin_smith,(= (float 1.0) (double 1.0))
15:26clojurebottrue
15:26kwladykadysfun yes but not after any change in files during editing
15:26RedNifre,3/3
15:26clojurebot1
15:26RedNifre,1/3
15:26clojurebot1/3
15:26dysfunwell maybe you don't want that
15:26justin_smithRedNifre: it's a syntax for creating rationals, rationals autopromote to longs as applicable
15:26dysfuni find it really useful
15:26RedNifrewat
15:26dysfuni like real time feedback
15:26RedNifrewhy do rationals autopromote to longs but floats don't?
15:27kwladykadysfun if it is very small app it could be ok
15:27justin_smithRedNifre: rationals are exact
15:27justin_smithRedNifre: floats are lossy
15:27justin_smith,(+ 1/3 2/3)
15:27clojurebot1N
15:27dysfunkwladyka: i don't understand why must it be small?
15:27RedNifre,1N
15:27clojurebot1N
15:27kwladykadysfun what if tests take 30 second and run after any change in any files?
15:27justin_smithRedNifre: are you familiar with the pitfalls of ieee floating point? eg. why you should hardly ever compare them for equality?
15:27RedNifreNow hang on, if 1N doesn't turn into 1, why is (= 1 1N) true?
15:27kwladykait will be iritating
15:27dysfunif your tests take 30 seconds, you're doing them wrong
15:28luma,(+ 0.1 0.2)
15:28clojurebot0.30000000000000004
15:28RedNifreyes, I'm aware of that.
15:28dysfunmost of mine run basically instantaneously
15:28justin_smithRedNifre: because they are on the same side of the exact/inexact divide
15:28kwladykadysfun i can't agree with that :)
15:28justin_smithRedNifre: there is no lossless translation across that divide
15:28kwladykadysfun because it is simple app
15:28dysfunmostly i develop libraries actually
15:28justin_smithRedNifre: but we treat two numbers on the same side as equal
15:28RedNifrewell, there is sometimes. So I guess clojure is being consistent by pretending that you can never translate lossless?
15:29dysfunobviously if you have to have a database etc. it will take longer
15:29kwladykadysfun if you count more complex algorithm or do more complex things it takes a time
15:29RedNifreI mean, I can understand that (= 1 (* 10 (/ 1.0 10.0))) would be false because of floating point inaccuracies.
15:29dysfunif you're doing machine learning, obviously you're not going to have it update in real time
15:29justin_smith,(= 1/2 0.5M) ; maybe this is wrong though, this totally could be treated as equal
15:29clojurebotfalse
15:30RedNifrewhat's M again?
15:30RedNifre...and what's N?
15:30kwladykai am going watch the movie. Thank you for discussion. I will be back after 2 hours :)
15:30justin_smith,(type 0.5M)
15:30clojurebotjava.math.BigDecimal
15:30justin_smith,(type 1N)
15:30clojurebotclojure.lang.BigInt
15:30RedNifreaha.
15:30justin_smithboth are lossless numbers
15:30RedNifreokay, so since floats are binary and BigDecimals are decimals I can see that they can't be compared for equality because that might be lossless.
15:31dysfunthe takeaway from all of this is : think before you write a comparison
15:31RedNifrewait, BigDecimal can't be lossless.
15:31justin_smithRedNifre: not just decimals, auto-promoting so that they don't lose data (up to some limit)
15:31justin_smithright, there is actually a limit
15:31dysfunthey definitely at that range
15:32justin_smithRedNifre: instead of losing precision, bigdecimal will just fall over
15:32justin_smith,(/ 1.0M 2.0M)
15:32clojurebot0.5M
15:32RedNifreOkay, so the way I understand it is this: If a comparison could lead to a wrong result because of lossy representation the comparison will always be false even if it would actually be a precise comparison in the concrete case.
15:32justin_smith,(/ 1.0M 5.0M)
15:32clojurebot0.2M
15:32justin_smithhmm...
15:32RedNifre,(/ 1.0M 3.0M)
15:32justin_smith,(/ 1.0M 3.0M)
15:32clojurebot#error {\n :cause "Non-terminating decimal expansion; no exact representable decimal result."\n :via\n [{:type java.lang.ArithmeticException\n :message "Non-terminating decimal expansion; no exact representable decimal result."\n :at [java.math.BigDecimal divide "BigDecimal.java" 1616]}]\n :trace\n [[java.math.BigDecimal divide "BigDecimal.java" 1616]\n [clojure.lang.Numbers$BigDecimalOps div...
15:32clojurebot#error {\n :cause "Non-terminating decimal expansion; no exact representable decimal result."\n :via\n [{:type java.lang.ArithmeticException\n :message "Non-terminating decimal expansion; no exact representable decimal result."\n :at [java.math.BigDecimal divide "BigDecimal.java" 1616]}]\n :trace\n [[java.math.BigDecimal divide "BigDecimal.java" 1616]\n [clojure.lang.Numbers$BigDecimalOps div...
15:32justin_smithright
15:33justin_smithRedNifre: that sounds about right, yeah
15:33RedNifreThat's funny, so BigDecimals avoids being lossy by crashing when it would get lossy?
15:34RedNifre,(* 10.0 (/ 1.0 10.0))
15:34clojurebot1.0
15:34dysfunif you're hitting the limit, you weren't checking your inputs sufficiently
15:34RedNifre,(/ 1.0 10.0)
15:34clojurebot0.1
15:35RedNifreIs "1.0" a float or a BigDecimal?
15:35justin_smith,(* 3 1/3)
15:35clojurebot1N
15:35justin_smith1.0 is double
15:35dysfunwell it's a string, but without the quotes it would be a double
15:35justin_smithI guess float prints that way too, but clojure strongly prefers doubles
15:35dysfunthere's little reason to prefer floats
15:36RedNifrewasn't 0.1 rounded to a double something like 0.1000000000000000000004 ?
15:36justin_smithyeah, I think that's some kind of printing rule
15:36dysfunthere isn't much reason to scrimp on integers these days tbh
15:36RedNifre,(= 10.0 (* 10.0 (/ 1.0 10.0)))
15:36clojurebotfalse
15:36dysfun(unless you're abusing pointer packing, in which case i salute you)
15:36RedNifre,(= 1.0 (* 10.0 (/ 1.0 10.0)))
15:36clojurebottrue
15:37RedNifreMaybe I'm thinking about some other binary floating point issue, but I thought 1 / 10 * 10 wasn't 1 in IEEE?
15:37dysfunyou shouldn't be testing floats for equality anyway
15:38justin_smith,(format "%20.420f" 0.1)
15:38clojurebot"0.1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
15:38justin_smithsorry
15:39RedNifredysfun I know, but I thought the reason was that (= 1.0 (* 10.0 (/ 1.0 10.0))) would be false because of float inaccuracies, so I'm surprised that it works.
15:40RedNifreI also think that clojurebot's output has more precision than a double.
15:40dysfunoh, it's one of those things where it often does, but you shouldn't rely on it
15:40dysfunthat makes for very difficult to diagnose bugs
15:40justin_smithRedNifre: I asked for a specific number of zeros
15:40dysfunanyway, hometime
15:41RedNifrejustin_smith can you elaborate?
15:42RedNifrewhat exactly did clojurebot output there? Was it a double?
15:42justin_smithRedNifre: I ran ,(format "%20.420f" 0.1) which asks for a specific number of digits, padded with zeros even after precision runs out
15:42justin_smithRedNifre: it outputted a string, as format returns string
15:42justin_smith"outputted" I R SMRT
15:45RedNifreWell, my internet connection is too slow to google the precision of JVM doubles but if it's 64 bit then I don't understand how clojurebot can output something so close to 0.1 from a double.
15:47RedNifreAnother thing, does "==" compare exactly, or does it compare within the precision of IEEE?
15:47justin_smith(Double/mulp 0.1)
15:47justin_smith,(Double/mulp 0.1)
15:47clojurebot#error {\n :cause "No matching method: mulp"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.IllegalArgumentException: No matching method: mulp, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.IllegalArgumentException\n :message "No matching method: mulp"\n :at [clojure.lang.Compiler$StaticMet...
15:47justin_smitherr...
15:47RedNifre,(Double/ulp 0.1)
15:47clojurebot#error {\n :cause "No matching method: ulp"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.IllegalArgumentException: No matching method: ulp, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.IllegalArgumentException\n :message "No matching method: ulp"\n :at [clojure.lang.Compiler$StaticMethod...
15:47RedNifreworth a shot...
15:48justin_smith,(Math/ulp 0.1)
15:48clojurebot1.3877787807814457E-17
15:48RedNifreright, so it's 17 decimal digits. But clojureput output way more than 17 zeroes, so how does that work?
15:48justin_smith,(-> 0.1 (- 1.3877787807814457E-17) (+ 1.3877787807814457E-17))
15:48clojurebot0.1
15:48justin_smithRedNifre: like I said I used format, format says "give me this many zeros on a string"
15:49justin_smithclojurebot gave me a string, not a double
15:49RedNifreah, you mean it first "rounds" it to the string "0.1" and then just adds zeros for fun?
15:49justin_smithRedNifre: I was hoping using a long format would expose precision, but we got 0.1 back anyway
15:50justin_smithso yeah, pretty much
15:50justin_smithnot for fun, because my format string said add that many zeros
15:50RedNifreokay, so how CAN you expose precision?
15:51justin_smithlooking at the ulp? getting the raw bits and the implementation rules and doing the math?
15:51justin_smithnot sure
15:51justin_smithactually going this time, be back soon when I get to the office
15:53rotcevhi, say i have a list in the form of ((+ 1) (+ 2) (- 3)), what is the best way to get it into the form (+ 1 (+ 2 (- 3))), ive been trying for a while but cant seem to come up with a nice way
15:54RedNifrehm, maybe reverse it and reduce it with something like apply or invoke or -> or ->>?
15:56rotcevRedNifre: at the moment im doing http://hastebin.com/uverajaziw.lisp with input of (infix (1 + 2 + 3 - 5)) which results in ((+ 1) (+ 2) (- 3) (5))
15:56RedNifrehang on, I'm new to this so I need a moment to think :)
15:56rotcevwhich isnt even ideal tbh cos ideally the 5 would be paired in with the 3 but im kinda new to clojure so i dont know how to work partition to the way i need it (unless i should go about it a diff way)
15:56RedNifreyour link gives me an application error.
15:56RedNifrebut I'm also on a bad connection.
15:57rotcevit just worked for me site just went down lol ill pastebin it
15:57rotcevRedNifre: http://pastebin.com/sibdb4Ci
15:58RedNifreHm, looks like (reduce -> ... doesn't work because "->" is a macro...
15:59amalloyi don't think you can really transform your list in that way efficiently. it's not too hard to do inefficiently
16:00rotcevmy ideal output would be (+ 1 (+ 2 (- 3 5))) so i could just use eval on it
16:01rotcever not even, itd be ( + 1 ( + 2 ( - 3 5))) or something no need to eliminate spaces
16:02rotcevi was thinking itd be cool if i could somehow treat each list as a partial function
16:02rotcevis there some way to do that in clojure? (in this specific case)
16:03RedNifreIs there something like hoogle for clojure?
16:04rotcevclojuredocs
16:06mgaarerotcev: do you need to consider order of operations? in other words, will you ever see multiplication, division, more parens, etc?
16:06amalloyRedNifre: nothing nearly as good
16:06RedNifrewell, how do I append a form to a list?
16:07RedNifreI can only think about insane ways involving cons and reverse.
16:07rotcevmgaare: probably but i was thinking it would just be the order of the expressions in reverse for operator precedence
16:08rotcevand since i was just gonna use eval to read it i kinda assumed it would end up magicly working in the end lol
16:09RedNifreah, I'm making progress here... let me think this through...
16:12rotcevi think im making progress too ;o
16:12amalloywhy are you trying to munge this list around into a form that's suitable to eval? using eval is rarely a good answer, and getting it into shape for eval is harder than just evaluating it yourself with reduce
16:14rotcevtrue i just wasnt thinking correctly lol
16:14amalloy,(let [ops {'+ + '- -}] (reduce (fn [acc [op x]] ((ops op) acc x)) 0 '((+ 1) (+ 2) (- 3))))
16:14clojurebot0
16:16RedNifre,'(1 2)
16:16clojurebot(1 2)
16:16RedNifre,'('(1 2))
16:16clojurebot((quote (1 2)))
16:16RedNifreWhat's up whith that "quote"?
16:16RedNifreWhy isn't it ((1 2)) ?
16:17RedNifre...ooooh
16:17RedNifre,'((1 2))
16:17clojurebot((1 2))
16:17amalloythat's how quoting works. it's not just the "make a list" operator
16:17RedNifreAh, that solves everything.
16:17amalloy'('(1 2)) is shorthand for (quote (quote (1 2)))
16:18RedNifrerotcev I think I got it!
16:18rotcev:o
16:18RedNifre...though my solution is probably a bit crazy.
16:18RedNifre,(defn append [x,l] (reverse (cons x (reverse l))))
16:18clojurebot#'sandbox/append
16:19RedNifre(reduce append (reverse '((+ 1) (+ 2) (- 3))))
16:19rotcevthe reverses rofl
16:19RedNifre,(reduce append (reverse '((+ 1) (+ 2) (- 3))))
16:19clojurebot(+ 1 (+ 2 (- 3)))
16:19RedNifretadaa!
16:20rotcevnice
16:20RedNifreyeah, I guess there is already something like that append function in clojure, but I coludn't find it.
16:20RedNifre,(append (+ 1) (- 2))
16:20clojurebot#error {\n :cause "Don't know how to create ISeq from: java.lang.Long"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "Don't know how to create ISeq from: java.lang.Long"\n :at [clojure.lang.RT seqFrom "RT.java" 542]}]\n :trace\n [[clojure.lang.RT seqFrom "RT.java" 542]\n [clojure.lang.RT seq "RT.java" 523]\n [clojure.core$seq__4357 invokeStatic "core.clj" 137]\n [clojure.co...
16:20RedNifre,(append '(+ 1) '(- 2))
16:20clojurebot(- 2 (+ 1))
16:21mgaareRedNifre: could also use concat, like
16:21RedNifreI tried concat, but that unpacket the second list too.
16:22mgaare,(defn append-cat [x xs] (concat xs (list x)))
16:22clojurebot#'sandbox/append-cat
16:22amalloyRedNifre: http://stackoverflow.com/q/5734435/625403
16:22mgaare,(append-cat '(+ 1) '((+ 2) (- 3)))
16:22clojurebot((+ 2) (- 3) (+ 1))
16:23RedNifremgaare oh, so you wrap the list in a list to counteract concat's flattening?
16:23mgaareno, you wrap the single thing you're trying to append in a list
16:24mgaarealthough amalloy was kind enough to point out some shortcomings in that approach in that link ;)
16:33rotcevthanks for the guidance anyways guys i think i know another way to solve it which im trying to implement now
16:43RedNifreconnection broke down
16:48justin_smithRedNifre: the standard way to append to a list is (concat l [e]), but if you know you will be doing only appends, it's easier to just make a vector and conj
16:48justin_smithoops, scrollback
16:48justin_smithmaybe still relevant though...
16:48justin_smith,(defn append' [l & args] (concat l args))
16:48clojurebot#'sandbox/append'
16:48RedNifreyeah, you missed my first clojure solution for somebody else's problem.
16:49justin_smith,(append' '(:a :b :c) :d :e :f)
16:49clojurebot(:a :b :c :d :e ...)
16:49RedNifre,(append' '(+ 2) '(- 3))
16:49clojurebot(+ 2 (- 3))
16:50RedNifreah, it's backwards compared to mine.
16:50RedNifreI still have the Haskell convention in my head: First the special things, then the large data structures to operate on.
16:51RedNifreHow would you solve the original problem with your append?
16:51justin_smithRedNifre: (reduce append' ...)
16:51justin_smithRedNifre: instead of reversing etc.
16:52RedNifreI'm now at the macro part of the tutorial. Could everything that can be done with macros also be done with regular functions and quoted source code?
16:52justin_smithRedNifre: if you are allowed to use eval, yes
16:52RedNifre,(reduce append' '((+ 1) (+ 2) (- 3)))
16:52clojurebot(+ 1 (+ 2) (- 3))
16:52justin_smithotherwise other macros will trip you up sometimes
16:53justin_smithRedNifre: that's not right is it
16:53RedNifrenot quite, huh?
16:53RedNifreIs there a reduce-left?
16:53justin_smith,(defn put-in [[a b] el] [a el b])
16:53clojurebot#'sandbox/put-in
16:53RedNifreah, so macros are better in that case because they expand at compile time so you don't need eval?
16:54justin_smith,(reduce put-in '((+ 1) (+ 2) (- 3)))
16:54clojurebot[+ (- 3) (+ 2)]
16:54justin_smithstill not it
16:54justin_smithyeah I guess the reversing is needed regardless
16:55RedNifreI think you have to reduce/fold from the right, otherwise you have to drill into your nested lists with different depth each step.
16:55justin_smithright
16:56justin_smith,(reduce put-in (reverse '((+ 1) (+ 2) (- 3))))
16:56clojurebot[- (+ 1) (+ 2)]
16:56justin_smithhaha, well
16:57justin_smithright, so your answer was the one then
16:57RedNifrewait, where did the 3 go?
16:57RedNifre,'[(1 2)]
16:57clojurebot[(1 2)]
16:57justin_smithRedNifre: disappeared in a destructure that made a bad assumption
16:57justin_smith,(let [[a b] [1 2 3]] [a b])
16:57clojurebot[1 2]
17:00RedNifreI'm now reading about ' quoting and ` syntax quoting. So I can interpolate with ~ in ` but not in '. Why does ~ not work in '?
17:00justin_smithbecause it's a special syntax that only exists inside `
17:00justin_smithjust like you can only catch inside try
17:02justin_smith,'```(do :a)
17:02clojurebot(clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/seq)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/concat)) (clojure.core/list (clojure.core/seq (clojure.core/concat (clojure.core/list (quote clojure.core/list)) (clojure.core/list (clojure.core/seq #))))) (clojure.core/list (clojure.core/seq (clojure.core/concat (clo...
17:03RedNifre,(inc 1)
17:03clojurebot2
17:04RedNifreWell, would there be a downside to '(1 ~(inc 1)) producing (1 2) ?
17:04justin_smithRedNifre: it would mean ' only exists in order to create crappy name capture that causes bugs
17:05lodin-RedNifre: I guess the question is why not use `(1 ~(inc 1)).
17:05justin_smithas it is, name capture isn't an issue (at least less trivially an issue) because ' does not interpolate
17:05RedNifreBut then my question would be why not always use ` instead of '?
17:06justin_smithRedNifre: ` does interpolation and also namespace qualifying
17:06justin_smithit's much more complicated
17:06lodin-RedNifre: Because `x resolves x, while 'x is a literal symbol.
17:06justin_smith,'`(do :a) ; compare this to the next
17:06clojurebot(clojure.core/seq (clojure.core/concat (clojure.core/list (quote do)) (clojure.core/list :a)))
17:06justin_smith,''(do :a)
17:06clojurebot(quote (do :a))
17:07lodin-RedNifre: Maybe resolves is not right. justin_smith said it better.
17:07RedNifre,'x
17:07clojurebotx
17:07RedNifre,`x
17:07clojurebotsandbox/x
17:07lodin-,'(let [x 1])
17:07clojurebot(let [x 1])
17:07lodin-,`(let [x 1])
17:07clojurebot(clojure.core/let [sandbox/x 1])
17:07lodin-The second will give you an error.
17:08RedNifreah, so quoting is more like source code whose meaning depends on where it gets executed while syntax quoting actually works out precisely what each form means?
17:09justin_smithRedNifre: somewhat - there's a history of buggy macros that "capture" surrounding values
17:09justin_smithgoing way back into LISP times
17:09justin_smithsyntax quoting, which resolves things at macro definition, is a way of preventing these bugs
17:10RedNifreIt's all a bit muddy to me, I still don't understand why I wouldn't just use syntax quoting always. Why would the second one of lodin-'s example give me an error?
17:10justin_smithRedNifre: you can't use a fully qualified symbol as a local binding
17:11justin_smiththe reason ` turns it into a fully qualified symbol is to keep it from shadowing local bindings
17:11lodin-RedNifre: The thing is, you would not want to get (clojure.core/let [x 1]) either, because then you (might) shadow an x.
17:12justin_smithimagine you have (defn foo [a] (frob (+ a a))) and then (defmacro frob [form] `(let [a "dog"] (~form))) and a inside the macro was not modified
17:12justin_smiththe macro would end up compiling to (+ "dog" "dog")
17:12justin_smithbecause it captures a symbol
17:13justin_smiththe original a is inaccessible in the macro, since the name is shadowed
17:13justin_smithI think there's more than one mistake in that example, but I hope you get the gist of it
17:14RedNifreI'm not sure, the macro looks like you want to shadow a? Or what is (let [a "dog"]... meant to achieve?
17:15justin_smithRedNifre: the example is bad and it should feel bad, imagine a was somehow useful in that macro.
17:16RedNifreWell, I see how a gets shadowed but I don't understand the implications.
17:16justin_smithRedNifre: it means implementation details of a macro you call (the names it gives internal bindings) change the meaning of code that calls it.
17:16lodin-RedNifre: The macro author does not know what the user will or won't have in the form. So no names would be safe.
17:17justin_smithwhere some magic binding name leads to totally different behaviors
17:17RedNifrecan you give an example of how you would write your example to prevent that problem?
17:17lodin-RedNifre: This is why we have a#.
17:17lodin-,`(let [x# 1])
17:17clojurebot(clojure.core/let [x__25__auto__ 1])
17:17justin_smithRedNifre: (defmacro frob [form] `(let [a# "dog"] (~form))) - a# expands to a gensym, a guaranteed globally unique symbol
17:17RedNifrehmmm... so in my syntax quoted macros I should add a # to variable names to prevent shadowing?
17:17lodin-RedNifre: So never use names like __<somenumber>__auto__ :-)
17:18justin_smithRedNifre: you need to add a # or it will refuse to even compile
17:18justin_smithlodin-: gensym is smart enough to still make a name that doesn't conflict if you do that though
17:18justin_smithafaik
17:18lodin-Would be the most confusing macroexpanded code ever though. :-)
17:18RedNifreBut what if I want to do (frob (str "Hey " a ", go fetch!")) ?
17:19justin_smithRedNifre: it would tell you a is unbound
17:19justin_smithRedNifre: clojure doesn't like spooky action at a distance, we do lots of things that discourage it
17:19justin_smithor make it difficult to implement
17:19lodin-RedNifre: So if you *do* want to use a "local" name, then you can do that, by interpolating a literal symbol. And there are legitimate reasons for doing that.
17:19RedNifreI'm surprised, I thought macros just rewrote the syntax tree.
17:20justin_smithRedNifre: "just" - we are very opinionated about how that "should" happen - but yeah, if you use regular ' you can make anything work
17:20justin_smithand the bugs this inevitably causes are now your burden
17:20RedNifreBut it sounds like a sensible restrictions, I mean, getting extra stuff from a macro would be strange.
17:20lodin-,`(let [~'x 1])
17:20clojurebot(clojure.core/let [x 1])
17:21justin_smithRedNifre: lodin-: great example of legit use of intentional shadowing is the #() reader macro
17:21justin_smith,'#(+ % %)
17:21clojurebot(fn* [p1__74#] (+ p1__74# p1__74#))
17:21justin_smithin that example, % was magic, and refers to a binding the compiler creates
17:22justin_smithwe accept it as given that % will be the first arg in the generated function, and substituted smartly in the function body
17:22RedNifreOkay, so... a macro may rearrange what you put into it but it won't/shouldn't add anything surprising?
17:22justin_smithwell, that's getting into philosophy I guess...
17:22justin_smithhaha
17:23justin_smithbut yes, best to avoid surprises, just as with any other code I'd think
17:23RedNifreWhat I mean is you can't do (library-in-a-macro (foo "look, the macro gave me a foo function I can use!"))
17:23justin_smithright, that's probably a bad idea
17:24RedNifreI'm not sure if I understood if that's even possible or not.
17:24RedNifreI think you said not using # at the end of "foo" would be a compile error, but there is intentional shadowing in some reader?
17:26RedNifreThe macro can't do "(let [foo println]" because that won't compile, right? So how would the macro provide a foo function to the... what's it called, macro content?
17:26lodin-RedNifre: By interpolating a (unqualified) symbol.
17:27lodin-,(defmacro foo [form] `(let [~'x 42] ~form))
17:27clojurebot#'sandbox/foo
17:28lodin-,(foo x)
17:28clojurebot42
17:29RedNifreI guess it'll take some time until I aquire an intuition for what I should and shouldn't do with macros...
17:30justin_smithRedNifre: two groups of people should write macros - novices who need to figure out what the hell the deal is with macros, and masters of the language who need to offer new syntax back to the community. In between they are almost always a mistake.
17:30lodin-RedNifre: If you write a program that, you know, actually do useful stuff, you don't need to write any macro. the clojure.core macros plus functional abstraction will take you pretty far.
17:30justin_smithyeah, exactly
17:31justin_smithbut the awesome thing is, when someone sees that we need eg. core.async or core.logic, the tools are there to do it within the regular language, without forking it
17:32justin_smithbecause those things would be pretty useless without the new syntaxes which make their features usable
17:36RedNifreSo do you people use clojure at the office?
17:37justin_smithRedNifre: right now I should be writing clojure code but am procrastinating
17:37justin_smithliterally sitting at my desk in the office
17:37RedNifreWell, how did clojure take hold in your office? Or did your company always use some lisp or other fp language?
17:37justin_smiththey decided to convert the ruby app to clojure, so then they hired me to make it happen
17:38RedNifreAh, ruby to clojure makes sense I guess.
17:38RedNifre(I was asking because I'm having a hard time imagining my java office even consider something like clojure)
17:38justin_smithRedNifre: it was a bundle of ruby services making up an app, someone converted one to clojure because it needed to be concurrent, they saw how much faster development was on that service, the lower defect rate, and the better performance, and eventually opted to redo the rest of it too
17:38DynamicMetaFlowWhat factors would lead someone to go from a Ruby app to Clojure?
17:39justin_smithRedNifre: the two big things would be dev time and defect rate, even in a java environment
17:39justin_smithDynamicMetaFlow: wanting to spend less money on servers, faster dev on mature apps with lower defect rate (immutability helps a lot here)
17:40justin_smithDynamicMetaFlow: on the other hand, the initial ramp-up for a proof of concept is much faster with ruby - that hits a limit for most devs though
17:40DynamicMetaFlowWhat do you mean by "ramp-up for a proof of concept
17:41DynamicMetaFlowDo you mean prototyping or something else
17:41justin_smithDynamicMetaFlow: going from "we should make an app that does X" to having a first prototype
17:41justin_smithexactly, prototyping
17:41justin_smithso ruby probably prototypes faster, but clojure is more likely to end up with something maintainable (if done idiomatically), and can be almost as fast to prototype
17:41DynamicMetaFlowThat's interesting, I've heard claims of the same fast prototyping in Clojure
17:42justin_smithDynamicMetaFlow: sure, but I think with things like rails, you can really get a first proof of concept of something that looks slick and has all the moving parts very fast
17:42justin_smithclojure can compete, but I don't think it's quite as instant
17:43DynamicMetaFlowYeah, I've picked up Python but haven't practiced in a while. I did learn a little Ruby and then made a complete switch to Common Lisp and now I want to entertain Clojure because of the JVM. At this point though I just need to sit with one language
17:43justin_smithDynamicMetaFlow: yeah, that makes sense. All the stuff the jvm makes available is pretty useful if you need modern libraries - because the jvm has libs for just about everything.
17:43DynamicMetaFlowThat's a good point. I remember someone in a podcast saying that Rails is what popularized Ruby and to an effect clojurescript will hopefully do the same for Clojure. It was an interesting podcast
17:44justin_smithDynamicMetaFlow: yeah, I think cljs, plus reagent and figwheel and ring could do that
17:45DynamicMetaFlowRight now I'm thinking of learning more Ruby to at least help out in different projects to contribute to but long term make the switch to Clojure
17:46justin_smithcool, hope you stick with the plan to learn clojure, and find it as rewarding as many of us here have
17:47rotcevwhat's some good stuff to read on macros, i want to learn about unquoting or w/e idk what thats all about
17:47RedNifreCurrently, Ruby is my go-to language for very small things (scripts with a couple hundred lines) because Ruby's focus is on programmer happiness and everything's allowed.
17:47DynamicMetaFlowI feel that when I was learning Common Lisp it's mental models is what worked in my head
17:47RedNifreI wouldn't use it for anything large though.
17:48justin_smithrotcev: the classic is "On Lisp" by that guy who founded y combinator
17:48justin_smithturns out he knows a shitload about macros
17:48DynamicMetaFlowHas anyone gone through this course from Eric Normand, http://www.purelyfunctional.tv/
17:48justin_smiththe book is about common lisp, but it's all pretty easy to adjust to if you know clojure
17:48rotcevis a macro a lisp thing or a clojure specific feature
17:49RedNifreHm, the "clojure for the brave and true" seems to be very theoretical. If I want to get my hands dirty and write a tiny command line program that uses a sqlite database, where would I start?
17:49justin_smithDynamicMetaFlow: I've heard great things about it, but have not. I do remember Eric Normand from when he hung out in this channel, and he knows his shit.
17:49justin_smithRedNifre: google for "clojure sqlite binding", check out the readme?
17:49RedNifreE.g. for node.js, the process was: 1. Find library on npm 2. ask on freenode where they tell you that the popular npm library is garbage 3. use what freenode recommends.
17:49DynamicMetaFlowYeah, I listened to him on a podcast and I liked his thoughts regarding How to teach someone in programming
17:50justin_smithRedNifre: oh, a good ingredient here is going to the project for that lib on clojars and see how many downloads it has, and also going on crossclj.info to see what reputable libs and apps use it
17:50RedNifreis there something like hackage or npm for clojure?
17:50DynamicMetaFlowThis was the podcast I listened to, I highly recommend it. https://devchat.tv/ruby-rogues/232-rr-teaching-and-how-we-can-all-do-more-to-teach-technical-topics-to-others-with-eric-normand
17:50RedNifreah, thanks. I'll check it out.
17:51RedNifreYou people don't happen to know about any beginner friendly command line and sqlite libraries, huh?
17:52scottjrotcev: neither, other languages have macros too. macros in clojure are very similar to those in most other lisps though.
17:53scottjRedNifre: familiar with https://github.com/razum2um/awesome-clojure and clojure awesome ?
17:54RedNifreNo, I started some hours ago so I'm not familiar with anything.
17:54justin_smithrotcev: clojure macros are highly similar to common lisp macros, which is why paul graham's "on lisp" will likely teach you more than any other source I know of, but there is also some influence from scheme and the concept of hygeinic macros (though we don't use their model / syntax for that at all)
17:54scottjhttp://www.clojure-toolbox.com/
17:54rotcevcould someone briefly explain the answer to 'why macros'
17:54RedNifreAh, those links look excellent, thanks!
17:55RedNifrerotcev I think it's so you don't have to transform and then eval quoted source code.
17:55justin_smithor, alternately, fork the compiler
17:56rotcevdoes unquote just force an eval on a quote
17:56rotcev?
17:56justin_smithrotcev: macros allow the definition of new syntaxes. Which as you probably would guess isn't to often needed - but we constantly use those new syntaxes already developed, some which come with the language, some provided by libraries, all made with macros
17:56rotcevyeah i understand they are powerful thats why i want to be able to make my own
17:57rotcevxD
17:57justin_smithrotcev: a macro is a function that takes source code as an argument, and returns source code. the quote / unquote is a way of templating source code substitutions
17:58justin_smithbut it works on the level of forms, not strings as eg. C macros do
17:58RedNifreare there meta macros that generate macros?
17:58justin_smithsure
17:58justin_smithRedNifre: sometimes the only reason you need to write a macro is that the functionality you need is only provided by a macro, so you need another macro to extend it
17:58justin_smithRedNifre: for example if you want a new special kind of defn that extends the existing defn macro
17:59justin_smithyou could either recreate defn by scratch, or write a macro that expands to usage of defn
17:59justin_smithyou can't just use a function and be compatible with defn, of course
17:59justin_smithsince defn is a special syntax
17:59RedNifreHm, can a macro expand to two copies of itself, crashing the compiler?
17:59justin_smithRedNifre: I bet it's possible
18:00lodin-RedNifre: Macros can be recursive, yes, if that's what you mean.
18:00justin_smith,(defmacro boom [x] `((boom ~x) (boom ~x)))
18:00clojurebot#'sandbox/boom
18:01justin_smith,(boom 42)
18:01clojurebot#error {\n :cause nil\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.StackOverflowError, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6875]}\n {:type java.lang.StackOverflowError\n :message nil\n :at [java.util.regex.Pattern$5 isSatisfiedBy "Pattern.java" 5151]}]\n :trace\n [[java.util.regex.Pattern$5 isSatisfiedBy...
18:01justin_smithRedNifre: there you go
18:01justin_smithmacro-fork-bomb
18:02RedNifrehm, I wonder how hard it would be to find the bug. I'm not good at reading that error message but I guess in a real project it wouldn't tell you where the macro-fork-bomb happened, huh?
18:02RedNifreMeh, I guess there's always git bisect.
18:02justin_smithRedNifre: it would give you a line number instead of NO_SOURCE_PATH:0:0
18:02justin_smithand a file name
18:03RedNifreWhat's the limit of macros? I guess you couldn't compile ruby code using a macro since ruby has too many characters that have special meaning in clojure, e.g. ~ ?
18:03rotcevso is x in that example quoted source code, and the ~x unquotes it to be evaluated ?
18:04justin_smithyeah, you are limited to what works with the existing clojure reader rules, that all apply before macro expansion
18:04justin_smithrotcev: yes
18:04RedNifreokay, so no funky characters and the parens must match?
18:04justin_smithkind of
18:04lodin-RedNifre: The macro doesn't see any parens.
18:04lodin-RedNifre: The macro only sees Clojure data structures.
18:05RedNifreWhat I mean is that I could'n write a macro that works like (strange-macro )))))))
18:05lodin-RedNifre: This is a key point of this kind of macro.
18:05TEttingerlike (+ 1 #_ "whee" 1) returns 2
18:06TEttingerit only sees what it's been given, (+ 1 1), since the #_ reader macro ignores "whee"
18:07rotcev#_ means ignore next value ?
18:07TEttingerI'm not sure if there's anything like #_ possible in user-written macros
18:07TEttingeryeah, discard
18:07RedNifreOkay, so could I write a macro for BF code, i.e. (bf +++>>>+[.+]) or something like that?
18:07justin_smith,(+ 1 #_ anything-goes-here! 1)
18:07clojurebot2
18:07rotcevnice
18:07TEttingerhttps://yobriefca.se/blog/2014/05/19/the-weird-and-wonderful-characters-of-clojure/
18:07RedNifre,(+ 1 #_ ))))) 1 )
18:07clojurebot#<RuntimeException java.lang.RuntimeException: Unmatched delimiter: )>
18:07justin_smithRedNifre: well, the delimiters would have to work
18:08TEttingeryeah, #_ discards one form
18:08justin_smithRedNifre: I think bf has situations where combos of delimiter chars are allowed that would be illegal in clojure
18:08TEttinger,(+ 1 #_{:a [1 2 3]} 1)
18:08clojurebot2
18:08lodin-RedNifre: +++>>>+[.+] would be three things. First a symbol, +++>>>+, then a vector holding the symbol .+
18:08RedNifre,(+ 1 #_ ++>><<[+.]-- 1 )
18:08clojurebot#error {\n :cause "+."\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: +., compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.ClassNotFoundException\n :message "+."\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run "U...
18:09TEttingerlodin-: no, . isn't allowed in symbol names IIRC
18:09RedNifreokay, so inline bf would be impossible because it uses [ ] for loops.
18:09TEttinger,(defn a.b 1)
18:09clojurebot#error {\n :cause "Parameter declaration \"1\" should be a vector"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "Parameter declaration \"1\" should be a vector"\n :at [clojure.core$assert_valid_fdecl$fn__7207 invoke "core.clj" 7187]}]\n :trace\n [[clojure.core$assert_valid_fdecl$fn__7207 invoke "core.clj" 7187]\n [clojure.core$map$fn__4785 invoke "core.clj" 2646]\n [clojure...
18:09TEttinger,(def a.b 1)
18:09clojurebot#'sandbox/a.b
18:09TEttingeroh nvm
18:09TEttinger,a.b
18:09clojurebot#error {\n :cause "a.b"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.ClassNotFoundException: a.b, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6688]}\n {:type java.lang.ClassNotFoundException\n :message "a.b"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run...
18:09TEttingerah ok
18:09justin_smithRedNifre: as lodin- said that's three forms
18:09TEttingerit "allows" infix dot
18:09TEttingerbut not really
18:10justin_smith,(+ 1 #_#_#_ ++>><<[+.]-- 1 ) ; RedNifre
18:10clojurebot2
18:10justin_smithone #_ per form
18:10TEttingernice trick, justin_smith
18:11rotcevso what is the difference between ` and '
18:12TEttingerRedNifre: this type of thing is a good use for just using a string as a sequence of chars, since BF is all one-char operators anyway right?
18:12RedNifrehm, so macros would make it trivial to write something like Haskell's do-notation...
18:12TEttingerrotcev: I really liked brave clojure's walk through that stuff
18:12lodin-RedNifre: And it has been done, kind of.
18:12rotcevkk
18:12justin_smithRedNifre: we do have monad libs, I don't know how far they go syntax wise though
18:13TEttingerhttp://www.braveclojure.com/writing-macros/
18:13lodin-justin_smith: I've seen one library that goes pretty far in the Haskell direction, even using <- to bind.
18:14justin_smithlodin-: fascinating
18:14Glenjaminhttp://www.leonardoborges.com/writings/2012/12/08/monads-in-small-bites-part-iv-monads/ appears to have something like do notation
18:15lodin-justin_smith: It looks pretty alien in Clojure code though.
18:17RedNifreWell, in Haskell the problem was that you had nested lambdas i.e. (bind (getSomething) (fn [something] (bind (process something) (fn [another-thing]...))))))) and do-notation turns that into (monadic-do (<- something getSomething) (<- another-thing process something) ...)
18:17RedNifreOkay, I think I now see the value of macros :)
18:18lodin-RedNifre: :-)
18:29lodin-RedNifre: The same nesting would occur in Clojure, but there's no IO monad in Clojure, everything is Maybe (can be nil), and list has it's own do-notation in disguise (the for macro). And let is ordered and allows rebinding, so it is OK to do (let [state (init-state 5), [state v] (get state), state (put state 3)] ...).
18:32RedNifrelodin- Well, I'm not sure, couldn't it be done without nesting? Let me write an example...
18:32lodin-RedNifre: What I'm saying is that monads are treated case by case.
18:33lodin-RedNifre: Not if you want a bind operation and code that would do the same as you Haskell example.
18:34RedNifrelodin- I wrote an example, would it be possible to write a macro that turns the second code into the first?: http://pastebin.com/PRz2UAEV
18:34clojurebotNo entiendo
18:34lodin-RedNifre: Monads are less useful in Clojure though since you can't infer which return to use, hence case by case.
18:34lodin-RedNifre: Of course, see the link given by Glenjamin above.
18:35RedNifreIn my example, if I used some promise library that came with that "then" function, could I write that macro just for that one case?
18:35RedNifreah, I somehow missed that link. one sec.
18:37lodin-RedNifre: I mean that without using a macro (i.e. introducing do notation in Clojure), the Clojure code would have the same problem.
18:37lodin-RedNifre: It's just like justin_smith said, the benefit of macros is that you don't need a language update to provide it, you only need a library.
18:38RedNifreAh, okay, then I understand what you mean.
18:39RedNifreWell, it's getting late. Thank you all for your help, good night/day/etc.!
18:47justin_smithso I found this twitter account that just posts random pictures from unprotected webcam feeds, and this post it just made is basically me rn https://twitter.com/FFD8FFDB/status/696117413931315200
19:11noncom|2what do you think about scala, people? i have heard that clojure and scala do complement each other.. what are your thoughts?
19:11noncom|2(note: i've been 2.5 years scala, and now i'm 2.5 years of clojure)
19:12noncom|2i am looking at the messages that i still occasionally receive from scala mailing list and stuff... and they seem soo contrived and convoluted :/
19:12justin_smithnoncom|2: I wish it was feasible to write individual things in scala then use them via clojure, but it seems like scala is hard to use from other jvm langs
19:12noncom|2of course, much of this comes because of the type system and stuff..
19:13justin_smithnoncom|2: or, maybe I'm misinformed and that is actually a straightforward thing to do?
19:13noncom|2hmmm i am not really sure about that.
19:13noncom|2WOW https://t6.github.io/from-scala/
19:14noncom|2well, i guess i understand - scala is ALL about syntax sugar... and when you deal with what this sugar resolves to.. here comes the pains
19:14noncom|2but this lib seems ilke a bridge..
19:15noncom|2well, one more issue i see, is that scala compiler is a sooooo demanding machine..
19:15noncom|2it can drain all your computer resources for just barely printing several symbols inside some of the sugared clauses
19:16noncom|2i remember typing hell instead some pattern-matched json destructor.. i was literally getting 1 char in 1-2 seconds or so
19:16noncom|2(the presentation compiler i mean here, the class one might be heavier but runs once in a while)
19:17noncom|2s/instead/inside
19:17noncom|2eh.. sleepy
19:20noncom|2justin_smith: could you maybe answer a web-specific question? i have a login form made with cljs+bootstrap.. how do i enable password saving in it?
19:21justin_smithnoncom|2: the way I handle that is not create the login page with cljs - that way I'm not sending the full app to a user that isn't logged in
19:22justin_smithside effect is normal plain old html login page where the browser save-this-password just works
19:22noncom|2hmmm, interesting
19:22justin_smithnoncom|2: so the flow is - plain html login, if login succeeds redirect to the single page app and send them all the js etc.
19:23noncom|2ok, i got it.. heh, i'll have to rewrite this bunch of stuff this way... but do you maybe know, how does the browser distinguish?
19:23justin_smithnoncom|2: I'm sure there is a way to make the browser save passwords in a react app, but this is why I haven't had to figure that out
19:23noncom|2ah
19:23noncom|2well okay
19:24justin_smithnoncom|2: but your case might be different - I have a webapp as a service, so it makes sense not to send the js until they auth
19:24justin_smiththat makes the auth questions in the server side much simpler
19:25noncom|2justin_smith: in my case it makes sense too. i just did not design it the way you did - the login form is a part of the jsapp. i think your way is more correct and i have to change to it. but it may be not as easy task as i expected, but certainlyk doable
19:27noncom|2justin_smith: eh, just FYO: http://timothy.userapp.io/post/63412334209/form-autocomplete-and-remember-password-with another html/js hell there. i am certainly taking up your way. thanks for the hint!
19:27justin_smithnoncom|2: nice to know I dodged that bullet
20:04justin_smithlol http://www.foaas.com/
20:07TEttingeroh my god Ballmer
20:07justin_smithlol
20:08justin_smithTEttinger: oh that's awesome I hadn't gotten to that one yet
20:12justin_smithTEttinger: https://www.refheap.com/114550
20:13justin_smithI know that in the real world there is no such rivalry
20:16TEttingernice
20:18visof,(partition 2 1 [1 2 3 4 5 6])
20:18clojurebot((1 2) (2 3) (3 4) (4 5) (5 6))
20:19visof,(map (fn [xs] (first xs)) (partition 2 1 [1 2 3 4 5 6]))
20:19clojurebot(1 2 3 4 5)
20:20justin_smith,(map first (partition 2 1 [1 2 3 4 5 6])) ; (fn [xs] (first xs)) is a weird way to write first
20:20clojurebot(1 2 3 4 5)
20:21visofjustin_smith: yeah that's neater, but fn i'm planning to do more complex things than first
20:22justin_smithk
20:26amalloyspeaking of weird ways to write a thing, i recently fixed a bunch of tests that looked like: (is (= true (every? true? (map #(f x %) ys))))
20:26justin_smithso with partition 2 1, the first element will only show up once, as the first element of the first pair, and the last will also only show up once, and the last element of the last pair
20:26amalloya poor way to write (is (every? #(f x %) ys))
20:27justin_smithamalloy: wow, double whammy there
20:29justin_smith(boolean (is (= true (boolean (every? true? (doall (map #(boolean (f x %)) (seq ys)))))))) ; ftw
20:30justin_smithno, justin_smith, there is no winning this game and there is always a way to add silly complexity
20:32justin_smithoh man - cljs : (inc :1) => ":11"
20:33justin_smithI mean you deserve it if you make a terrible keyword like :1, but wow that's gross
21:40Bronsajustin_smith: wow :/
21:54kenrestivojustin_smith: ugh
23:26rhg135that's... disturbing