#clojure log - Feb 06 2016

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

6:40 benjyz1: hello. I'm wrestling with SQL in Clojure

6:40 jdbc/insert! for some reason doesn't commit to my database

6:41 https://www.refheap.com/114533

6:42 do I need some kind of commit?

6:45 ok, nevermind, just some weird error

6:46 mmeix: (makedb) etc is commented out

6:46 ah .. ok

9:29 thomasfuston: Are there recommended ways to build GUI applictions with clojure?

9:46 dysfun: thomasfuston: if by that you mean 'non-browser applications', it's not recommendable

9:46 CaptainLex: Hehe I was going to say

9:46 thomasfuston: hmm so its better to have a browserinterface? even to a local app?

9:47 dysfun: no, it's better to write the app in not-clojure

9:47 thomasfuston: ok, you saying clojure is best for webdevelopement

9:48 dysfun: i'm saying clojure is ideal for anything where startup time is not a primary requirement

9:48 and that don't require you to write a gui

9:48 unless it's a web one

9:49 the 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

9:51 thomasfuston: well 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

9:51 dysfun: in practice, if you want a crossplatform gui application, you use qt

9:52 i think the java bindings are pretty outdated last i checked

9:52 and it causes all sorts of deployment issues

9:54 for 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

9:54 of course currently i'm building the web client... in clojure+clojurescript

9:55 the server, well that's a clojure webservice

9:56 honestly i'm finding it easier to build for the web than build the clients, significantly so

10:10 CaptainLex: dysfun: What about using other Clojure targets, like PyClojure? Do those projects still have any momentum?

10:31 rhg135: I'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:32 dysfun: CaptainLex: i'm not convinced they're going anywhere

10:33 i've personally got an llvm-clojure project on the back burner

10:33 CaptainLex: dysfun: True, but for thomasfuston's purposes - building a GUI app just to get his hands dirty - it might be useful.

10:34 dysfun: or, y'know, he could use python, which is a more suited tool for his purpose and he happens to know

11:18 arkh: or, y'know, it could be a fun project to learn more clojure

11:19 ridcully: never

12:41 benjyz1: hello. 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:44 https://www.refheap.com/114540

12:44 justin_smith: benjyz1: the input to the handler won't be js, so js->cljs doesn't help

12:45 benjyz1: you need to use js/JSON to turn the string into js data

12:45 because it will just be a string

12:45 (or you can use whichever cljs wrapper for js/JSON you like of course)

12:54 benjyz1: thanks. trying with "(js/JSON.parse response)"

12:56 justin_smith: yeah, that sounds right

12:59 benjyz1: Unexpected string... when I try to parse {"foo" "bar"}

12:59 justin_smith: well that's not valid json

12:59 are you sending edn format?

12:59 in that case, you want cljs.reader/read-string or whatever it's called

13:00 or you could fix your middleware so you actually send json

13:01 benjyz1: I'm trying (wrap-json-response)

13:02 justin_smith: OK, are you setting the content-type header?

13:02 you might need to make sure your accept header is right on the client side too, I forget

13:06 benjyz1: I was looking around whether I can find a template which integrates ring and CLJS

13:11 macrolicious: does anyone know which rainbow delimiters mode works well in emacs -nw (in a terminall… iterm2 in my case)?

13:11 justin_smith: macrolicious: it should just be a question of adjusting the faces defined by rainbow-delimiters mode right?

13:12 macrolicious: ah ok… too noob to know that… sweet...

13:13 justin_smith: macrolicious: M-x customize-group<return>rainbow-delimeters<return>

13:14 then from there go to reainbow-delimiters-faces, and edit and preview to hearts content

13:15 macrolicious: it's also possible to customize these things outside of the customize interface, but customize is handy especially when new to emacs

13:16 macrolicious: that's really helpful… and I'll be able to pick the right faces...

13:46 * djbkd waves

13:47 kwladyka: What 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:48 i think send options is better

13:48 *second

13:49 maybe even like that (defn create-uuid! [uidable-id uidable-type type [expired-in_n expired-in_time-unit]]

13:49 justin_smith: why not (defn create-uuid! [uidable-id uidable-type type [n time-unit :as expired-in]] ...)

13:50 kwladyka: it is better, thanks!

13:52 djbkd: i'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:52 justin_smith: djbkd: the lein-ring plugin is broken with the latest lein

13:53 djbkd: ah ok

13:53 justin_smith: djbkd: if you "upgrade" to an older lein that fixes it

13:53 djbkd: hahaha

13:53 so, like nodejs :c

13:53 https://twitter.com/BadKittyDaddy/status/696041540896993280

13:53 justin_smith: hopefully the next ring will fix this :)

13:53 djbkd: sad timing for the new lein breakage, with that great book coming out...

13:54 djbkd: yeah i really like clj as a language

13:54 but such is the nature of open source

13:54 kwladyka: Anybody from Switzerland here? I am wonder how looks Clojure work there.

13:54 djbkd: i'll try downgrading, thanks

14:02 macrolicious: justin_smith: got my delimiters all looking pretty… took a bit to figure out the customization interface, but yay!

14:02 RedNifre: If 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:03 justin_smith: RedNifre: you don't need a zip

14:04 RedNifre: lein is a shell file

14:04 RedNifre: oh, so if I have lein I'm all set?

14:04 justin_smith: RedNifre: if you are using lein, lein finds and uses whichever version of clojure your project config tells it to

14:04 so yeah, if using lein, just the script suffices

14:04 RedNifre: I don't have a project config yet, I'm starting with clojure right now :)

14:05 okay, sounds good, I'll see how far I get...

14:05 justin_smith: RedNifre: 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:05 RedNifre: right, lein has a default clojure it will use, but once you create a project the project needs to declare a clojure version

14:06 RedNifre: if not using a project and therefore not having any deps, yeah, just use clojure.jar, use rlwrap too that makes it nicer

14:06 but 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:08 RedNifre: I 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:08 dysfun: lein is my benchmark for build tools now

14:08 justin_smith: RedNifre: it is much better than the default usage of any of those, but cabal used properly is probably lein's equal :)

14:09 dysfun: but noone uses cabal properly, that's why we have stack :)

14:09 justin_smith: (properly meaning, no sharing of deps implicitly between projects, all things sandboxed but artifacts of same version shared via a cache)

14:09 dysfun: you know, you'd probably quite like stack

14:10 justin_smith: I'm sure, I'm still a n99b at haskell though

14:10 odometer hasn't even rolled over to n00b yet

14:10 dysfun: right, well even more reason to use stack. it's the best way to get started these days

14:10 justin_smith: cool

14:10 RedNifre: Possible, I heard about it peripherily. I also heard something about some cabal nix crossover thingy, does stack work well with nixOS as well?

14:11 dysfun: and the truth is that once you grok the syntax, just tweak monads until the type works and stop worrying about it

14:11 justin_smith: RedNifre: 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:11 dysfun: i'm not a nixos user, but loads of hackage has nixos builds

14:12 besides, i'm too busy solving problems with haskell to be a haskell programmer

14:13 RedNifre: Unfortunately I haven't used Haskell in about a year :/

14:14 dysfun: justin_smith: https://github.com/jjl/ctaas/blob/master/src/Main.hs 53 lines in memory hashtable webservice

14:14 justin_smith: anyway, clojure's great, isn't that why we're all here?

14:14 RedNifre: maybe? :)

14:14 dysfun: haskell has a different useful niche

14:15 justin_smith: back 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:15 RedNifre: I'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:16 dysfun: ah yeah, i pissed him off once by saying "fucking haskell programmers"

14:16 justin_smith: RedNifre: right, clojure is a great mix of tidy enough to be sane while pliable enough to do things quickly and refine later, imho

14:16 dysfun: clojure is my preferred tool when it's a good fit

14:17 RedNifre: That sounds a bit like a tautology.

14:17 justin_smith: dysfun: "x is my preferred too when it's a good fit" is a low information statement :)

14:17 dysfun: not really. it says "if clojure isn't disqualified, i'll pick it"

14:18 RedNifre: ah, you mean "if it isn't a bad fit"?

14:18 justin_smith: dysfun: oh, perhaps we understand "a good fit" differently

14:18 RedNifre: get out of my brain

14:18 bbl

14:20 RedNifre: dito

14:25 Oh no. What exactly happens when I do "lein run"? How much data does it download?

14:26 Ah 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:26 mmastic: I'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:27 RedNifre: Well, 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:28 justin_smith: RedNifre: I'd just use "rlwrap java -jar clojure-1.8.0.jar" for now

14:28 when you have a good connection, do the full deal

14:28 (with lein)

14:28 RedNifre: Hm, 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:28 kwladyka: is any reason why "contains?" work only with one key...?

14:29 RedNifre: justin_smith what does that command do exactly?

14:29 justin_smith: RedNifre: starts a clojure repl

14:30 no other things available except the extensive libs offered by the vm itself

14:30 it'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:30 lodin-: kwladyka: Huh?

14:31 justin_smith: lodin-: kwladyka wants (contains? m k1 k2 k3)

14:31 which doesn't work of course

14:31 kwladyka: lodin- exactly like justin_smith said

14:31 lodin-: And what would be true if m contained all keys?

14:31 justin_smith: I don't know why, I agree varargs would be nice

14:31 amalloy: justin_smith: i think varargs there would be bad

14:32 lodin-: s/what/that/

14:32 amalloy: because there are two reasonable meanings: (every? #(contains? m %) ks), or (some #(contains? m %) ks)

14:32 lodin-: Precisely, what amalloy said.

14:32 justin_smith: amalloy: I hadn't considered some being expected

14:33 noncom|2: is 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:33 *java/joda

14:33 RedNifre: (if (contains? food :peanuts :seafish) (dont-eat food))

14:35 dysfun: obviously that's a too few parameters to if exception waiting to happen

14:36 lodin-: dysfun: Being sarcastic?

14:37 dysfun: well yes, but it is.

14:37 RedNifre: how so?

14:37 amalloy: dysfun: it's not

14:37 ,(if true 1)

14:37 clojurebot: 1

14:38 dysfun: maybe it's just clojurescript that complains

14:38 justin_smith: dysfun: no, cljs doesn't complain

14:38 dysfun: maybe you are thinking of haskell

14:39 RedNifre: :D

14:39 dysfun: i'm really not. i've just spent two days fixing clojure to work under cljs

14:39 RedNifre: ,(if false 1)

14:39 clojurebot: nil

14:39 lodin-: dysfun: Not that I would complain if it complained. The opposite, actually.

14:39 justin_smith: dysfun: 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:40 *another dev

14:40 dysfun: well i can't explain the error messages i've received then

14:40 justin_smith: if he was a def I could have prevented him from going out of scope, but now we have to hire a guy

14:40 dysfun: perhaps it was too many args to if

14:40 dysfun: ah yeah, could be

14:40 RedNifre: What's a def and how does single branch if relate to not using when?

14:41 justin_smith: RedNifre: haha, I typod def for dev, as in coworker

14:41 dysfun: well a single branch if would act as a when, so the idea is not needed when

14:41 RedNifre: ah, missed the correction, now it makes sense :)

14:41 justin_smith: RedNifre: (when p? (f)) is the same as (if p? (f)), when is only different when it has more than one form

14:41 RedNifre: and my ex coworker hated when

14:42 dysfun: i quite like when

14:42 justin_smith: and would use single branch if instead, we argued about it

14:43 my 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:43 so it's a reading comprehension gain

14:43 dysfun: agreed

14:43 RedNifre: I don't know enough about when to have an opinion on this yet. :)

14:44 dysfun: the truth is life is too short to really care

14:44 justin_smith: the 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:44 RedNifre: horray, lein downloaded 1.8.0 and executed my example lein project and it outputted "Hello world!".

14:44 justin_smith: nice

14:45 * RedNifre makes a note that when on a bad network connection, just retry the lein commands until you get lucky.

14:45 dysfun: yeah, that's a good strategy for many tools

14:45 mmastic: Is there perhaps anyone here that came from Haskell?

14:46 dysfun: i came back to clojure after taking some time out to do haskell

14:46 justin_smith: RedNifre: 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:47 RedNifre: mmastic yes, me, sort of.

14:47 mmastic: Oh, 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:47 dysfun: justin_smith: well it would have failed its checksum then wouldn't it?

14:47 justin_smith: the 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:47 dysfun: hell, without a pom how would I get a checksum? the pom files contained html too

14:47 dysfun: mmastic: you tend to worry more about the shape of things than their type

14:48 right, but it's never going to find the checksum matches, is it?

14:48 RedNifre: mmastic no idea, I'm on the first page of a clojure tutorial here.

14:48 justin_smith: mmastic: 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:48 mmastic: usually this is implicit because we are using code whose primitives are all defined in terms of thse protocols and multimethods

14:49 RedNifre: Which 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:49 * FiredBall-0x71 http://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:49 justin_smith: but sometimes you get low level enough to need to define your own protocols / multimethods / interfaces, or extend them

14:49 mmastic: Oh 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:49 dysfun: justin_smith: is that low level?

14:49 justin_smith: RedNifre: I am unaware of any actual repl color feature outside of maybe editor integration

14:50 mmastic: lists are a protocol

14:50 etc.

14:50 mmastic: dysfun: Are you referring to the collection abstractions?

14:50 dysfun: mmastic: protocols are useful for mimicking existing behaviour

14:50 justin_smith: mmastic: so it's lispy by using protocols :)

14:50 dysfun: yes

14:50 RedNifre: hm, maybe the tutorial just enabled syntax highlighting for every piece of clojure code which accidentally colored the repl listings there.

14:50 dysfun: it's basedo n what justin_smith is saying

14:51 RedNifre: Why is it called "-main" and not "main" or something like that?

14:51 mmastic: Yeah but it's not Lispy to define protocols for your data, right? it's all about maps, is that correct?

14:51 justin_smith: mmastic: 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:52 mmastic: 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:52 dysfun: RedNifre: 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:52 FiredBall-0x71: join ##astara prince

14:52 http://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:52 RedNifre: dysfun I see, thanks.

14:52 justin_smith: mmastic: lispy is that the only data structure you have is a list

14:52 lodin-: 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:52 justin_smith: mmastic: clojure extends that to "everything implements seq" (within reason)

14:52 via seq, we can treat everything as a list if needed

14:53 dysfun: when we say lispy in clojure, i think we mean more 'makes good use of builtins'

14:53 justin_smith: mmastic: and maps and lists are protocols, in clojure

14:53 so it's a false dichotomy

14:53 dysfun: "doesn't reinvent the wheel" perhaps

14:54 or "knows when to reinvent the wheel" :)

14:54 justin_smith: mmastic: 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:55 mmastic: Ah 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:55 dysfun: yeah, for example you can treat a map as a list, it contains a vector of [key value]

14:55 RedNifre: Not 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:55 Basically, you indent the code like in python or haskell and the parens appear by themselves.

14:56 justin_smith: dysfun: mmastic: and that map -> ([k v] [k v]) transition maps directly to the idiom of alists in lisp

14:56 lodin-: 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:56 justin_smith: RedNifre: I look forward to using it when it's mature maybe, it looks like a cool concept

14:56 lodin-: mmastic: I can clarify that I think this mostly applies when you cross library boundaries.

14:56 justin_smith: lodin-: well, even "map" is a protocl, not a concrete data type

14:57 mmastic: And I assume a constructor function as-well, yeah?

14:57 justin_smith: mmastic: ?

14:57 RedNifre: Can 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:58 mmastic: justin_smith: Yup, I believe this is the case, however by map I just mean this kind of data-structure of pairs.

14:58 justin_smith: sure, right, and that's what that protocol means too

14:58 dysfun: if you like lisp, you'll like emacs.

14:59 but the real advantage of emacs is that it's very fast to edit text when you've learned certain shortcuts

14:59 and basically unusuable until you've learned the basics

15:01 mmastic: Thanks a lot for your help everyone; It's immensely appreciated.

15:01 RedNifre: Ah, 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:01 justin_smith: right, and it accepts any number of forms

15:01 RedNifre: If "when" is an else-less if, why is the "else" part of an "if" optional?

15:01 justin_smith: so that must clarify the above quite a bit

15:02 RedNifre: "any number of forms"

15:02 dysfun: (when (foo) (bar)) ; returns result of (bar)

15:02 justin_smith: (when p? (fire missiles) (issue apology to mother) (say goodbye) (exit))

15:02 each action is done in turn - wouldn't work in an if

15:02 RedNifre: Yeah, I think I understand that. I don't understand what you want to tell me by "any number of forms".

15:02 dysfun: (when (foo) (bar) (baz)) ; calls bar, then baz, returns (baz)

15:03 justin_smith: RedNifre: (f) is a form

15:03 RedNifre: Yes, I think I understand. And I could do (if bla (do a b c)), right?

15:03 justin_smith: sure, and that's what when is

15:03 when just looks nicer

15:03 RedNifre: Okay, 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:03 dysfun: these "not strictly necessary" things actually make clojure quite nice

15:04 RedNifre: Hm, I guess you can just comment out the "else" part, huh?

15:04 ...without rewriting it to a "when"...

15:04 justin_smith: RedNifre: no need for a comment...

15:04 ,(if true 1)

15:04 clojurebot: 1

15:05 justin_smith: ,(if false 1)

15:05 clojurebot: nil

15:05 RedNifre: No, 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:05 justin_smith: I mean, I guess, sure

15:05 dysfun: not if you use a line-comment like most people, because the parens need to match

15:06 RedNifre: ah, right, I had java style parens in mind.

15:06 so when to use an else-less if?

15:06 dysfun: you could use #_ though

15:06 justin_smith: ,(#_#_#_#_#_#_#_#_#_ we have better things than end of line comments)

15:06 clojurebot: ()

15:06 dysfun: lol

15:06 personally i won't be using the else-less if now i know about it

15:06 justin_smith: please don't use #_ like that, with the sole exception of commenting a matching binding/value pair in let or a hash map with #_#_

15:07 RedNifre: ,(#_ 1 2)

15:07 clojurebot: #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:07 justin_smith: RedNifre: that expands to (2)

15:07 RedNifre: thanks.

15:07 justin_smith: ,(#_#_ 1 2)

15:07 clojurebot: ()

15:07 justin_smith: my chain of #_ was perhaps less random than it looked

15:08 dysfun: do you like showing off in front of newbs?

15:08 RedNifre: how does that work exactly?

15:08 justin_smith: RedNifre: #_ eats exactly one form

15:08 RedNifre: so N #_ eats N forms

15:08 kwladyka: "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:08 RedNifre: why can you type them without spaces between them?

15:08 justin_smith: kwladyka: boot is a replacement for lein

15:09 dysfun: RedNifre: because the reader is special

15:09 justin_smith: RedNifre: they are reader macros, they don't obey the rules regular symbols do

15:09 RedNifre: another way to put it is for the same reason you can interchange [ [ ] ] with [[]]

15:10 RedNifre: Can you change as many as you want or are they defined separately, i.e. #_ and #_#_ and #_#_#_ up to, say 20 or something?

15:10 justin_smith: both are using the readers lowest level rules about where forms begin and end

15:10 RedNifre: *chain, not change

15:10 dysfun: in theory, they're not limited. in practice, who knows?

15:10 don't overuse them

15:10 justin_smith: RedNifre: there might be some stack overflow issue, I really shouldn't have even showed that silly #_#_#_#_#_ trick

15:11 dysfun: justin_smith: on a pushbackreader?

15:11 RedNifre: "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:11 justin_smith: RedNifre: same reason ( ( f ) ) is the same as ((f))

15:11 RedNifre: these are all reader rules

15:11 dysfun: or because there are special rules for interpreting parens and square barackets

15:12 RedNifre: hm, I'll ignore #_ for now...

15:12 justin_smith: RedNifre: 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:12 dysfun: when we say lisp has 'no syntax', we mean it has as little as we can get away with

15:12 justin_smith: exactly

15:13 RedNifre: Heh, I actually CAN comment the whole "else" line in an "if" because parinfer fixes the missing paren.

15:13 dysfun: nice

15:13 justin_smith: well there you go

15:13 but #_ can be more elegant sometimes

15:13 dysfun: and it works in all editors

15:14 RedNifre: alright

15:14 justin_smith: I am going to go to the office and try to catch up on my day job where I write clojure now. Yay!

15:14 dysfun: also use sparingly

15:15 RedNifre: Now 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:15 justin_smith: RedNifre: we don't have operators

15:15 = is a function

15:16 and it's more like the equals method

15:16 RedNifre: okay

15:16 justin_smith: ,(= () [])

15:16 RedNifre: so it's sane and I don't have to learn any special rules, huh?

15:16 clojurebot: true

15:16 justin_smith: RedNifre: is the above sane?

15:16 depending on your opinion of that, it may or may not be sane

15:16 ,(= 1.0 1)

15:16 clojurebot: false

15:17 RedNifre: hey!

15:17 Well, (= () []) 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:17 hmmmm...

15:17 dysfun: we say clojure data have value semantics - we always compare their values, not their references

15:17 justin_smith: structural equility for immutable things is pretty nice I think

15:17 * RedNifre ponders

15:18 justin_smith: dysfun: but haskell has that too, but it still wouldn't call two different types equal

15:18 which is where structural equality comes into play

15:18 structural equality is kind of cool but also weird but also useful

15:19 RedNifre: well, 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:19 justin_smith: I still find (= () []) and (not= 1 1.0) a quirky combo of behaviors :)

15:20 kwladyka: justin_smith replacement? More like another tool not replacement?

15:20 dysfun: i quite like 'shape typing'

15:20 RedNifre: What's the justification for (= 1 1.0) being false?

15:20 justin_smith: kwladyka: 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:20 dysfun: well for a start, floats are approximations of numbers :)

15:20 RedNifre: but in this case it approximates 1 perfectly.

15:21 neoncont_: justin_smith: is (= ["structural equality" "isomorphism"])?

15:21 justin_smith: RedNifre: for another potentially confusing detail, we have == for numeric value equality that ignores type

15:21 kwladyka: justin_smith just not sure about idea of boot. Is not better to have lein + CI instead of boot?

15:21 i didn't use boot so i don't know details

15:21 dysfun: kwladyka: boot is like lein, but different

15:21 justin_smith: ,(== 1 1.0 3/3)

15:21 clojurebot: true

15:21 dysfun: since i started porting my stuff to support clojurescript, i find boot a better fit

15:22 RedNifre: okay, but can I use == on other things?

15:22 justin_smith: kwladyka: boot starts faster, has a cleaner implementation, and is imperative instead of declarative. Some people like these things.

15:22 dysfun: it doesn't start faster here

15:22 justin_smith: RedNifre: no, only Number instances

15:22 dysfun: perhaps I was misled

15:22 kwladyka: dysfun can you give more details why?

15:22 RedNifre: If (= 1 1.0) is false and (== 1 1.0) is true I would expect (= () []) to be false and (== () []) to be true.

15:22 dysfun: they're both slow here

15:23 justin_smith: RedNifre: that would be consistent but sadly is not the case

15:23 dysfun: kwladyka: because i get to have one watcher to update everything

15:24 kwladyka: dysfun watcher?

15:24 dysfun: for instance i have a task that watches for updates and then runs the clojure tests and then the clojurescript ones

15:24 justin_smith: RedNifre: 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:24 RedNifre: you can't say the same about number types

15:24 dysfun: a watcher is simply a builtin boot facility that watches for file changes

15:24 RedNifre: Well, 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:24 kwladyka: dysfun and that is the point. Isn't it job for CI software like teamcity ?

15:24 dysfun oh in that way

15:24 dysfun: RedNifre: they're not a bad set really, but always ask what you want

15:25 kwladyka: dysfun if i know lein can do the same with cljs

15:25 dysfun: kwladyka: no, boot is like leiningen

15:25 you do want to run your tests before you push them don't you?

15:25 justin_smith: RedNifre: 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:25 RedNifre: also, = works between numeric subtypes that agree on the exact / lossy divide

15:25 ,(= 1 3/3)

15:25 clojurebot: true

15:25 justin_smith: ,(= 1 1N)

15:25 clojurebot: true

15:25 RedNifre: wat

15:26 justin_smith: ,(= (float 1.0) (double 1.0))

15:26 clojurebot: true

15:26 kwladyka: dysfun yes but not after any change in files during editing

15:26 RedNifre: ,3/3

15:26 clojurebot: 1

15:26 RedNifre: ,1/3

15:26 clojurebot: 1/3

15:26 dysfun: well maybe you don't want that

15:26 justin_smith: RedNifre: it's a syntax for creating rationals, rationals autopromote to longs as applicable

15:26 dysfun: i find it really useful

15:26 RedNifre: wat

15:26 dysfun: i like real time feedback

15:26 RedNifre: why do rationals autopromote to longs but floats don't?

15:27 kwladyka: dysfun if it is very small app it could be ok

15:27 justin_smith: RedNifre: rationals are exact

15:27 RedNifre: floats are lossy

15:27 ,(+ 1/3 2/3)

15:27 clojurebot: 1N

15:27 dysfun: kwladyka: i don't understand why must it be small?

15:27 RedNifre: ,1N

15:27 clojurebot: 1N

15:27 kwladyka: dysfun what if tests take 30 second and run after any change in any files?

15:27 justin_smith: RedNifre: are you familiar with the pitfalls of ieee floating point? eg. why you should hardly ever compare them for equality?

15:27 RedNifre: Now hang on, if 1N doesn't turn into 1, why is (= 1 1N) true?

15:27 kwladyka: it will be iritating

15:27 dysfun: if your tests take 30 seconds, you're doing them wrong

15:28 luma: ,(+ 0.1 0.2)

15:28 clojurebot: 0.30000000000000004

15:28 RedNifre: yes, I'm aware of that.

15:28 dysfun: most of mine run basically instantaneously

15:28 justin_smith: RedNifre: because they are on the same side of the exact/inexact divide

15:28 kwladyka: dysfun i can't agree with that :)

15:28 justin_smith: RedNifre: there is no lossless translation across that divide

15:28 kwladyka: dysfun because it is simple app

15:28 dysfun: mostly i develop libraries actually

15:28 justin_smith: RedNifre: but we treat two numbers on the same side as equal

15:28 RedNifre: well, there is sometimes. So I guess clojure is being consistent by pretending that you can never translate lossless?

15:29 dysfun: obviously if you have to have a database etc. it will take longer

15:29 kwladyka: dysfun if you count more complex algorithm or do more complex things it takes a time

15:29 RedNifre: I mean, I can understand that (= 1 (* 10 (/ 1.0 10.0))) would be false because of floating point inaccuracies.

15:29 dysfun: if you're doing machine learning, obviously you're not going to have it update in real time

15:29 justin_smith: ,(= 1/2 0.5M) ; maybe this is wrong though, this totally could be treated as equal

15:29 clojurebot: false

15:30 RedNifre: what's M again?

15:30 ...and what's N?

15:30 kwladyka: i am going watch the movie. Thank you for discussion. I will be back after 2 hours :)

15:30 justin_smith: ,(type 0.5M)

15:30 clojurebot: java.math.BigDecimal

15:30 justin_smith: ,(type 1N)

15:30 clojurebot: clojure.lang.BigInt

15:30 RedNifre: aha.

15:30 justin_smith: both are lossless numbers

15:30 RedNifre: okay, 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:31 dysfun: the takeaway from all of this is : think before you write a comparison

15:31 RedNifre: wait, BigDecimal can't be lossless.

15:31 justin_smith: RedNifre: not just decimals, auto-promoting so that they don't lose data (up to some limit)

15:31 right, there is actually a limit

15:31 dysfun: they definitely at that range

15:32 justin_smith: RedNifre: instead of losing precision, bigdecimal will just fall over

15:32 ,(/ 1.0M 2.0M)

15:32 clojurebot: 0.5M

15:32 RedNifre: Okay, 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:32 justin_smith: ,(/ 1.0M 5.0M)

15:32 clojurebot: 0.2M

15:32 justin_smith: hmm...

15:32 RedNifre: ,(/ 1.0M 3.0M)

15:32 justin_smith: ,(/ 1.0M 3.0M)

15:32 clojurebot: #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:32 #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:32 justin_smith: right

15:33 RedNifre: that sounds about right, yeah

15:33 * RedNifre sits in justin_smith's head.

15:33 RedNifre: That's funny, so BigDecimals avoids being lossy by crashing when it would get lossy?

15:34 ,(* 10.0 (/ 1.0 10.0))

15:34 clojurebot: 1.0

15:34 dysfun: if you're hitting the limit, you weren't checking your inputs sufficiently

15:34 RedNifre: ,(/ 1.0 10.0)

15:34 clojurebot: 0.1

15:35 RedNifre: Is "1.0" a float or a BigDecimal?

15:35 justin_smith: ,(* 3 1/3)

15:35 clojurebot: 1N

15:35 justin_smith: 1.0 is double

15:35 dysfun: well it's a string, but without the quotes it would be a double

15:35 justin_smith: I guess float prints that way too, but clojure strongly prefers doubles

15:35 dysfun: there's little reason to prefer floats

15:36 RedNifre: wasn't 0.1 rounded to a double something like 0.1000000000000000000004 ?

15:36 justin_smith: yeah, I think that's some kind of printing rule

15:36 dysfun: there isn't much reason to scrimp on integers these days tbh

15:36 RedNifre: ,(= 10.0 (* 10.0 (/ 1.0 10.0)))

15:36 clojurebot: false

15:36 dysfun: (unless you're abusing pointer packing, in which case i salute you)

15:36 RedNifre: ,(= 1.0 (* 10.0 (/ 1.0 10.0)))

15:36 clojurebot: true

15:37 RedNifre: Maybe I'm thinking about some other binary floating point issue, but I thought 1 / 10 * 10 wasn't 1 in IEEE?

15:37 dysfun: you shouldn't be testing floats for equality anyway

15:38 justin_smith: ,(format "%20.420f" 0.1)

15:38 clojurebot: "0.1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...

15:38 justin_smith: sorry

15:39 RedNifre: dysfun 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:40 I also think that clojurebot's output has more precision than a double.

15:40 dysfun: oh, it's one of those things where it often does, but you shouldn't rely on it

15:40 that makes for very difficult to diagnose bugs

15:40 justin_smith: RedNifre: I asked for a specific number of zeros

15:40 dysfun: anyway, hometime

15:41 RedNifre: justin_smith can you elaborate?

15:42 what exactly did clojurebot output there? Was it a double?

15:42 justin_smith: RedNifre: I ran ,(format "%20.420f" 0.1) which asks for a specific number of digits, padded with zeros even after precision runs out

15:42 RedNifre: it outputted a string, as format returns string

15:42 "outputted" I R SMRT

15:45 RedNifre: Well, 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:47 Another thing, does "==" compare exactly, or does it compare within the precision of IEEE?

15:47 justin_smith: (Double/mulp 0.1)

15:47 ,(Double/mulp 0.1)

15:47 clojurebot: #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:47 justin_smith: err...

15:47 RedNifre: ,(Double/ulp 0.1)

15:47 clojurebot: #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:47 RedNifre: worth a shot...

15:48 justin_smith: ,(Math/ulp 0.1)

15:48 clojurebot: 1.3877787807814457E-17

15:48 RedNifre: right, so it's 17 decimal digits. But clojureput output way more than 17 zeroes, so how does that work?

15:48 justin_smith: ,(-> 0.1 (- 1.3877787807814457E-17) (+ 1.3877787807814457E-17))

15:48 clojurebot: 0.1

15:48 justin_smith: RedNifre: like I said I used format, format says "give me this many zeros on a string"

15:49 clojurebot gave me a string, not a double

15:49 RedNifre: ah, you mean it first "rounds" it to the string "0.1" and then just adds zeros for fun?

15:49 justin_smith: RedNifre: I was hoping using a long format would expose precision, but we got 0.1 back anyway

15:50 so yeah, pretty much

15:50 not for fun, because my format string said add that many zeros

15:50 RedNifre: okay, so how CAN you expose precision?

15:51 justin_smith: looking at the ulp? getting the raw bits and the implementation rules and doing the math?

15:51 not sure

15:51 actually going this time, be back soon when I get to the office

15:53 rotcev: hi, 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:54 RedNifre: hm, maybe reverse it and reduce it with something like apply or invoke or -> or ->>?

15:56 rotcev: RedNifre: 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:56 RedNifre: hang on, I'm new to this so I need a moment to think :)

15:56 rotcev: which 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:56 RedNifre: your link gives me an application error.

15:56 but I'm also on a bad connection.

15:57 rotcev: it just worked for me site just went down lol ill pastebin it

15:57 RedNifre: http://pastebin.com/sibdb4Ci

15:58 RedNifre: Hm, looks like (reduce -> ... doesn't work because "->" is a macro...

15:59 amalloy: i don't think you can really transform your list in that way efficiently. it's not too hard to do inefficiently

15:59 * RedNifre thinks.

16:00 rotcev: my ideal output would be (+ 1 (+ 2 (- 3 5))) so i could just use eval on it

16:01 er not even, itd be ( + 1 ( + 2 ( - 3 5))) or something no need to eliminate spaces

16:02 i was thinking itd be cool if i could somehow treat each list as a partial function

16:02 is there some way to do that in clojure? (in this specific case)

16:03 * RedNifre is still thinking.

16:03 RedNifre: Is there something like hoogle for clojure?

16:04 rotcev: clojuredocs

16:06 mgaare: rotcev: do you need to consider order of operations? in other words, will you ever see multiplication, division, more parens, etc?

16:06 amalloy: RedNifre: nothing nearly as good

16:06 RedNifre: well, how do I append a form to a list?

16:07 I can only think about insane ways involving cons and reverse.

16:07 rotcev: mgaare: probably but i was thinking it would just be the order of the expressions in reverse for operator precedence

16:08 and since i was just gonna use eval to read it i kinda assumed it would end up magicly working in the end lol

16:09 RedNifre: ah, I'm making progress here... let me think this through...

16:12 rotcev: i think im making progress too ;o

16:12 amalloy: why 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:14 rotcev: true i just wasnt thinking correctly lol

16:14 amalloy: ,(let [ops {'+ + '- -}] (reduce (fn [acc [op x]] ((ops op) acc x)) 0 '((+ 1) (+ 2) (- 3))))

16:14 clojurebot: 0

16:16 RedNifre: ,'(1 2)

16:16 clojurebot: (1 2)

16:16 RedNifre: ,'('(1 2))

16:16 clojurebot: ((quote (1 2)))

16:16 RedNifre: What's up whith that "quote"?

16:16 Why isn't it ((1 2)) ?

16:17 ...ooooh

16:17 ,'((1 2))

16:17 clojurebot: ((1 2))

16:17 amalloy: that's how quoting works. it's not just the "make a list" operator

16:17 RedNifre: Ah, that solves everything.

16:17 amalloy: '('(1 2)) is shorthand for (quote (quote (1 2)))

16:18 RedNifre: rotcev I think I got it!

16:18 rotcev: :o

16:18 RedNifre: ...though my solution is probably a bit crazy.

16:18 ,(defn append [x,l] (reverse (cons x (reverse l))))

16:18 clojurebot: #'sandbox/append

16:19 RedNifre: (reduce append (reverse '((+ 1) (+ 2) (- 3))))

16:19 rotcev: the reverses rofl

16:19 RedNifre: ,(reduce append (reverse '((+ 1) (+ 2) (- 3))))

16:19 clojurebot: (+ 1 (+ 2 (- 3)))

16:19 RedNifre: tadaa!

16:20 rotcev: nice

16:20 RedNifre: yeah, I guess there is already something like that append function in clojure, but I coludn't find it.

16:20 ,(append (+ 1) (- 2))

16:20 clojurebot: #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:20 RedNifre: ,(append '(+ 1) '(- 2))

16:20 clojurebot: (- 2 (+ 1))

16:21 mgaare: RedNifre: could also use concat, like

16:21 RedNifre: I tried concat, but that unpacket the second list too.

16:22 mgaare: ,(defn append-cat [x xs] (concat xs (list x)))

16:22 clojurebot: #'sandbox/append-cat

16:22 amalloy: RedNifre: http://stackoverflow.com/q/5734435/625403

16:22 mgaare: ,(append-cat '(+ 1) '((+ 2) (- 3)))

16:22 clojurebot: ((+ 2) (- 3) (+ 1))

16:23 RedNifre: mgaare oh, so you wrap the list in a list to counteract concat's flattening?

16:23 mgaare: no, you wrap the single thing you're trying to append in a list

16:24 although amalloy was kind enough to point out some shortcomings in that approach in that link ;)

16:33 rotcev: thanks for the guidance anyways guys i think i know another way to solve it which im trying to implement now

16:43 RedNifre: connection broke down

16:48 justin_smith: RedNifre: 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:48 oops, scrollback

16:48 maybe still relevant though...

16:48 ,(defn append' [l & args] (concat l args))

16:48 clojurebot: #'sandbox/append'

16:48 RedNifre: yeah, you missed my first clojure solution for somebody else's problem.

16:49 justin_smith: ,(append' '(:a :b :c) :d :e :f)

16:49 clojurebot: (:a :b :c :d :e ...)

16:49 RedNifre: ,(append' '(+ 2) '(- 3))

16:49 clojurebot: (+ 2 (- 3))

16:50 RedNifre: ah, it's backwards compared to mine.

16:50 I still have the Haskell convention in my head: First the special things, then the large data structures to operate on.

16:51 How would you solve the original problem with your append?

16:51 justin_smith: RedNifre: (reduce append' ...)

16:51 RedNifre: instead of reversing etc.

16:52 RedNifre: I'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:52 justin_smith: RedNifre: if you are allowed to use eval, yes

16:52 RedNifre: ,(reduce append' '((+ 1) (+ 2) (- 3)))

16:52 clojurebot: (+ 1 (+ 2) (- 3))

16:52 justin_smith: otherwise other macros will trip you up sometimes

16:53 RedNifre: that's not right is it

16:53 RedNifre: not quite, huh?

16:53 Is there a reduce-left?

16:53 justin_smith: ,(defn put-in [[a b] el] [a el b])

16:53 clojurebot: #'sandbox/put-in

16:53 RedNifre: ah, so macros are better in that case because they expand at compile time so you don't need eval?

16:54 justin_smith: ,(reduce put-in '((+ 1) (+ 2) (- 3)))

16:54 clojurebot: [+ (- 3) (+ 2)]

16:54 justin_smith: still not it

16:54 yeah I guess the reversing is needed regardless

16:55 RedNifre: I think you have to reduce/fold from the right, otherwise you have to drill into your nested lists with different depth each step.

16:55 justin_smith: right

16:56 ,(reduce put-in (reverse '((+ 1) (+ 2) (- 3))))

16:56 clojurebot: [- (+ 1) (+ 2)]

16:56 justin_smith: haha, well

16:57 right, so your answer was the one then

16:57 RedNifre: wait, where did the 3 go?

16:57 ,'[(1 2)]

16:57 clojurebot: [(1 2)]

16:57 justin_smith: RedNifre: disappeared in a destructure that made a bad assumption

16:57 ,(let [[a b] [1 2 3]] [a b])

16:57 clojurebot: [1 2]

17:00 RedNifre: I'm now reading about ' quoting and ` syntax quoting. So I can interpolate with ~ in ` but not in '. Why does ~ not work in '?

17:00 justin_smith: because it's a special syntax that only exists inside `

17:00 just like you can only catch inside try

17:02 ,'```(do :a)

17:02 clojurebot: (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:03 RedNifre: ,(inc 1)

17:03 clojurebot: 2

17:04 RedNifre: Well, would there be a downside to '(1 ~(inc 1)) producing (1 2) ?

17:04 justin_smith: RedNifre: it would mean ' only exists in order to create crappy name capture that causes bugs

17:05 lodin-: RedNifre: I guess the question is why not use `(1 ~(inc 1)).

17:05 justin_smith: as it is, name capture isn't an issue (at least less trivially an issue) because ' does not interpolate

17:05 RedNifre: But then my question would be why not always use ` instead of '?

17:06 justin_smith: RedNifre: ` does interpolation and also namespace qualifying

17:06 it's much more complicated

17:06 lodin-: RedNifre: Because `x resolves x, while 'x is a literal symbol.

17:06 justin_smith: ,'`(do :a) ; compare this to the next

17:06 clojurebot: (clojure.core/seq (clojure.core/concat (clojure.core/list (quote do)) (clojure.core/list :a)))

17:06 justin_smith: ,''(do :a)

17:06 clojurebot: (quote (do :a))

17:07 lodin-: RedNifre: Maybe resolves is not right. justin_smith said it better.

17:07 RedNifre: ,'x

17:07 clojurebot: x

17:07 RedNifre: ,`x

17:07 clojurebot: sandbox/x

17:07 lodin-: ,'(let [x 1])

17:07 clojurebot: (let [x 1])

17:07 lodin-: ,`(let [x 1])

17:07 clojurebot: (clojure.core/let [sandbox/x 1])

17:07 lodin-: The second will give you an error.

17:08 RedNifre: ah, 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:09 justin_smith: RedNifre: somewhat - there's a history of buggy macros that "capture" surrounding values

17:09 going way back into LISP times

17:09 syntax quoting, which resolves things at macro definition, is a way of preventing these bugs

17:10 RedNifre: It'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:10 justin_smith: RedNifre: you can't use a fully qualified symbol as a local binding

17:11 the reason ` turns it into a fully qualified symbol is to keep it from shadowing local bindings

17:11 lodin-: RedNifre: The thing is, you would not want to get (clojure.core/let [x 1]) either, because then you (might) shadow an x.

17:12 justin_smith: imagine 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:12 the macro would end up compiling to (+ "dog" "dog")

17:12 because it captures a symbol

17:13 the original a is inaccessible in the macro, since the name is shadowed

17:13 I think there's more than one mistake in that example, but I hope you get the gist of it

17:14 RedNifre: I'm not sure, the macro looks like you want to shadow a? Or what is (let [a "dog"]... meant to achieve?

17:15 justin_smith: RedNifre: the example is bad and it should feel bad, imagine a was somehow useful in that macro.

17:16 RedNifre: Well, I see how a gets shadowed but I don't understand the implications.

17:16 justin_smith: RedNifre: it means implementation details of a macro you call (the names it gives internal bindings) change the meaning of code that calls it.

17:16 lodin-: 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:17 justin_smith: where some magic binding name leads to totally different behaviors

17:17 RedNifre: can you give an example of how you would write your example to prevent that problem?

17:17 lodin-: RedNifre: This is why we have a#.

17:17 ,`(let [x# 1])

17:17 clojurebot: (clojure.core/let [x__25__auto__ 1])

17:17 justin_smith: RedNifre: (defmacro frob [form] `(let [a# "dog"] (~form))) - a# expands to a gensym, a guaranteed globally unique symbol

17:17 RedNifre: hmmm... so in my syntax quoted macros I should add a # to variable names to prevent shadowing?

17:17 lodin-: RedNifre: So never use names like __<somenumber>__auto__ :-)

17:18 justin_smith: RedNifre: you need to add a # or it will refuse to even compile

17:18 lodin-: gensym is smart enough to still make a name that doesn't conflict if you do that though

17:18 afaik

17:18 lodin-: Would be the most confusing macroexpanded code ever though. :-)

17:18 RedNifre: But what if I want to do (frob (str "Hey " a ", go fetch!")) ?

17:19 justin_smith: RedNifre: it would tell you a is unbound

17:19 RedNifre: clojure doesn't like spooky action at a distance, we do lots of things that discourage it

17:19 or make it difficult to implement

17:19 lodin-: 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:19 RedNifre: I'm surprised, I thought macros just rewrote the syntax tree.

17:20 justin_smith: RedNifre: "just" - we are very opinionated about how that "should" happen - but yeah, if you use regular ' you can make anything work

17:20 and the bugs this inevitably causes are now your burden

17:20 RedNifre: But it sounds like a sensible restrictions, I mean, getting extra stuff from a macro would be strange.

17:20 lodin-: ,`(let [~'x 1])

17:20 clojurebot: (clojure.core/let [x 1])

17:21 justin_smith: RedNifre: lodin-: great example of legit use of intentional shadowing is the #() reader macro

17:21 ,'#(+ % %)

17:21 clojurebot: (fn* [p1__74#] (+ p1__74# p1__74#))

17:21 justin_smith: in that example, % was magic, and refers to a binding the compiler creates

17:22 we accept it as given that % will be the first arg in the generated function, and substituted smartly in the function body

17:22 RedNifre: Okay, so... a macro may rearrange what you put into it but it won't/shouldn't add anything surprising?

17:22 justin_smith: well, that's getting into philosophy I guess...

17:22 haha

17:23 but yes, best to avoid surprises, just as with any other code I'd think

17:23 RedNifre: What I mean is you can't do (library-in-a-macro (foo "look, the macro gave me a foo function I can use!"))

17:23 justin_smith: right, that's probably a bad idea

17:24 RedNifre: I'm not sure if I understood if that's even possible or not.

17:24 I think you said not using # at the end of "foo" would be a compile error, but there is intentional shadowing in some reader?

17:26 The 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:26 lodin-: RedNifre: By interpolating a (unqualified) symbol.

17:27 ,(defmacro foo [form] `(let [~'x 42] ~form))

17:27 clojurebot: #'sandbox/foo

17:28 lodin-: ,(foo x)

17:28 clojurebot: 42

17:29 RedNifre: I guess it'll take some time until I aquire an intuition for what I should and shouldn't do with macros...

17:30 justin_smith: RedNifre: 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:30 lodin-: 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:30 justin_smith: yeah, exactly

17:31 but 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:32 because those things would be pretty useless without the new syntaxes which make their features usable

17:36 RedNifre: So do you people use clojure at the office?

17:37 justin_smith: RedNifre: right now I should be writing clojure code but am procrastinating

17:37 literally sitting at my desk in the office

17:37 RedNifre: Well, how did clojure take hold in your office? Or did your company always use some lisp or other fp language?

17:37 justin_smith: they decided to convert the ruby app to clojure, so then they hired me to make it happen

17:38 RedNifre: Ah, ruby to clojure makes sense I guess.

17:38 (I was asking because I'm having a hard time imagining my java office even consider something like clojure)

17:38 justin_smith: RedNifre: 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:38 DynamicMetaFlow: What factors would lead someone to go from a Ruby app to Clojure?

17:39 justin_smith: RedNifre: the two big things would be dev time and defect rate, even in a java environment

17:39 DynamicMetaFlow: wanting to spend less money on servers, faster dev on mature apps with lower defect rate (immutability helps a lot here)

17:40 DynamicMetaFlow: 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:40 DynamicMetaFlow: What do you mean by "ramp-up for a proof of concept

17:41 Do you mean prototyping or something else

17:41 justin_smith: DynamicMetaFlow: going from "we should make an app that does X" to having a first prototype

17:41 exactly, prototyping

17:41 so 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:41 DynamicMetaFlow: That's interesting, I've heard claims of the same fast prototyping in Clojure

17:42 justin_smith: DynamicMetaFlow: 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:42 clojure can compete, but I don't think it's quite as instant

17:43 DynamicMetaFlow: Yeah, 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:43 justin_smith: DynamicMetaFlow: 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:43 DynamicMetaFlow: That'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:44 justin_smith: DynamicMetaFlow: yeah, I think cljs, plus reagent and figwheel and ring could do that

17:45 DynamicMetaFlow: Right 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:46 justin_smith: cool, hope you stick with the plan to learn clojure, and find it as rewarding as many of us here have

17:47 rotcev: what's some good stuff to read on macros, i want to learn about unquoting or w/e idk what thats all about

17:47 RedNifre: Currently, 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:47 DynamicMetaFlow: I feel that when I was learning Common Lisp it's mental models is what worked in my head

17:47 RedNifre: I wouldn't use it for anything large though.

17:48 justin_smith: rotcev: the classic is "On Lisp" by that guy who founded y combinator

17:48 turns out he knows a shitload about macros

17:48 DynamicMetaFlow: Has anyone gone through this course from Eric Normand, http://www.purelyfunctional.tv/

17:48 justin_smith: the book is about common lisp, but it's all pretty easy to adjust to if you know clojure

17:48 rotcev: is a macro a lisp thing or a clojure specific feature

17:49 RedNifre: Hm, 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:49 justin_smith: DynamicMetaFlow: 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:49 RedNifre: google for "clojure sqlite binding", check out the readme?

17:49 RedNifre: E.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:49 DynamicMetaFlow: Yeah, I listened to him on a podcast and I liked his thoughts regarding How to teach someone in programming

17:50 justin_smith: RedNifre: 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:50 RedNifre: is there something like hackage or npm for clojure?

17:50 DynamicMetaFlow: This 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:50 RedNifre: ah, thanks. I'll check it out.

17:51 You people don't happen to know about any beginner friendly command line and sqlite libraries, huh?

17:52 scottj: rotcev: neither, other languages have macros too. macros in clojure are very similar to those in most other lisps though.

17:53 RedNifre: familiar with https://github.com/razum2um/awesome-clojure and clojure awesome ?

17:54 RedNifre: No, I started some hours ago so I'm not familiar with anything.

17:54 justin_smith: rotcev: 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:54 scottj: http://www.clojure-toolbox.com/

17:54 rotcev: could someone briefly explain the answer to 'why macros'

17:54 RedNifre: Ah, those links look excellent, thanks!

17:55 rotcev I think it's so you don't have to transform and then eval quoted source code.

17:55 justin_smith: or, alternately, fork the compiler

17:56 rotcev: does unquote just force an eval on a quote

17:56 ?

17:56 justin_smith: rotcev: 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:56 rotcev: yeah i understand they are powerful thats why i want to be able to make my own

17:57 xD

17:57 justin_smith: rotcev: 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:58 but it works on the level of forms, not strings as eg. C macros do

17:58 RedNifre: are there meta macros that generate macros?

17:58 justin_smith: sure

17:58 RedNifre: 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:58 RedNifre: for example if you want a new special kind of defn that extends the existing defn macro

17:59 you could either recreate defn by scratch, or write a macro that expands to usage of defn

17:59 you can't just use a function and be compatible with defn, of course

17:59 since defn is a special syntax

17:59 RedNifre: Hm, can a macro expand to two copies of itself, crashing the compiler?

17:59 justin_smith: RedNifre: I bet it's possible

18:00 lodin-: RedNifre: Macros can be recursive, yes, if that's what you mean.

18:00 justin_smith: ,(defmacro boom [x] `((boom ~x) (boom ~x)))

18:00 clojurebot: #'sandbox/boom

18:01 justin_smith: ,(boom 42)

18:01 clojurebot: #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:01 justin_smith: RedNifre: there you go

18:01 macro-fork-bomb

18:02 RedNifre: hm, 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:02 Meh, I guess there's always git bisect.

18:02 justin_smith: RedNifre: it would give you a line number instead of NO_SOURCE_PATH:0:0

18:02 and a file name

18:03 RedNifre: What'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:03 rotcev: so is x in that example quoted source code, and the ~x unquotes it to be evaluated ?

18:04 justin_smith: yeah, you are limited to what works with the existing clojure reader rules, that all apply before macro expansion

18:04 rotcev: yes

18:04 RedNifre: okay, so no funky characters and the parens must match?

18:04 justin_smith: kind of

18:04 lodin-: RedNifre: The macro doesn't see any parens.

18:04 RedNifre: The macro only sees Clojure data structures.

18:05 RedNifre: What I mean is that I could'n write a macro that works like (strange-macro )))))))

18:05 lodin-: RedNifre: This is a key point of this kind of macro.

18:05 TEttinger: like (+ 1 #_ "whee" 1) returns 2

18:06 it only sees what it's been given, (+ 1 1), since the #_ reader macro ignores "whee"

18:07 rotcev: #_ means ignore next value ?

18:07 TEttinger: I'm not sure if there's anything like #_ possible in user-written macros

18:07 yeah, discard

18:07 RedNifre: Okay, so could I write a macro for BF code, i.e. (bf +++>>>+[.+]) or something like that?

18:07 justin_smith: ,(+ 1 #_ anything-goes-here! 1)

18:07 clojurebot: 2

18:07 rotcev: nice

18:07 TEttinger: https://yobriefca.se/blog/2014/05/19/the-weird-and-wonderful-characters-of-clojure/

18:07 RedNifre: ,(+ 1 #_ ))))) 1 )

18:07 clojurebot: #<RuntimeException java.lang.RuntimeException: Unmatched delimiter: )>

18:07 justin_smith: RedNifre: well, the delimiters would have to work

18:08 TEttinger: yeah, #_ discards one form

18:08 justin_smith: RedNifre: I think bf has situations where combos of delimiter chars are allowed that would be illegal in clojure

18:08 TEttinger: ,(+ 1 #_{:a [1 2 3]} 1)

18:08 clojurebot: 2

18:08 lodin-: RedNifre: +++>>>+[.+] would be three things. First a symbol, +++>>>+, then a vector holding the symbol .+

18:08 RedNifre: ,(+ 1 #_ ++>><<[+.]-- 1 )

18:08 clojurebot: #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:09 TEttinger: lodin-: no, . isn't allowed in symbol names IIRC

18:09 RedNifre: okay, so inline bf would be impossible because it uses [ ] for loops.

18:09 TEttinger: ,(defn a.b 1)

18:09 clojurebot: #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:09 TEttinger: ,(def a.b 1)

18:09 clojurebot: #'sandbox/a.b

18:09 TEttinger: oh nvm

18:09 ,a.b

18:09 clojurebot: #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:09 TEttinger: ah ok

18:09 justin_smith: RedNifre: as lodin- said that's three forms

18:09 TEttinger: it "allows" infix dot

18:09 but not really

18:10 justin_smith: ,(+ 1 #_#_#_ ++>><<[+.]-- 1 ) ; RedNifre

18:10 clojurebot: 2

18:10 justin_smith: one #_ per form

18:10 TEttinger: nice trick, justin_smith

18:11 rotcev: so what is the difference between ` and '

18:12 TEttinger: RedNifre: 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:12 RedNifre: hm, so macros would make it trivial to write something like Haskell's do-notation...

18:12 TEttinger: rotcev: I really liked brave clojure's walk through that stuff

18:12 lodin-: RedNifre: And it has been done, kind of.

18:12 rotcev: kk

18:12 justin_smith: RedNifre: we do have monad libs, I don't know how far they go syntax wise though

18:13 TEttinger: http://www.braveclojure.com/writing-macros/

18:13 lodin-: justin_smith: I've seen one library that goes pretty far in the Haskell direction, even using <- to bind.

18:14 justin_smith: lodin-: fascinating

18:14 Glenjamin: http://www.leonardoborges.com/writings/2012/12/08/monads-in-small-bites-part-iv-monads/ appears to have something like do notation

18:15 lodin-: justin_smith: It looks pretty alien in Clojure code though.

18:17 RedNifre: Well, 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:17 * RedNifre was enlightened.

18:17 RedNifre: Okay, I think I now see the value of macros :)

18:18 lodin-: RedNifre: :-)

18:29 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:32 RedNifre: lodin- Well, I'm not sure, couldn't it be done without nesting? Let me write an example...

18:32 lodin-: RedNifre: What I'm saying is that monads are treated case by case.

18:33 RedNifre: Not if you want a bind operation and code that would do the same as you Haskell example.

18:34 RedNifre: lodin- 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:34 clojurebot: No entiendo

18:34 lodin-: RedNifre: Monads are less useful in Clojure though since you can't infer which return to use, hence case by case.

18:34 RedNifre: Of course, see the link given by Glenjamin above.

18:35 RedNifre: In 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:35 ah, I somehow missed that link. one sec.

18:37 lodin-: RedNifre: I mean that without using a macro (i.e. introducing do notation in Clojure), the Clojure code would have the same problem.

18:37 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:38 RedNifre: Ah, okay, then I understand what you mean.

18:39 Well, it's getting late. Thank you all for your help, good night/day/etc.!

18:47 justin_smith: so 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:11 noncom|2: what do you think about scala, people? i have heard that clojure and scala do complement each other.. what are your thoughts?

19:11 (note: i've been 2.5 years scala, and now i'm 2.5 years of clojure)

19:12 i am looking at the messages that i still occasionally receive from scala mailing list and stuff... and they seem soo contrived and convoluted :/

19:12 justin_smith: noncom|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:12 noncom|2: of course, much of this comes because of the type system and stuff..

19:13 justin_smith: noncom|2: or, maybe I'm misinformed and that is actually a straightforward thing to do?

19:13 noncom|2: hmmm i am not really sure about that.

19:13 WOW https://t6.github.io/from-scala/

19:14 well, 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:14 but this lib seems ilke a bridge..

19:15 well, one more issue i see, is that scala compiler is a sooooo demanding machine..

19:15 it can drain all your computer resources for just barely printing several symbols inside some of the sugared clauses

19:16 i remember typing hell instead some pattern-matched json destructor.. i was literally getting 1 char in 1-2 seconds or so

19:16 (the presentation compiler i mean here, the class one might be heavier but runs once in a while)

19:17 s/instead/inside

19:17 eh.. sleepy

19:20 justin_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:21 justin_smith: noncom|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:22 side effect is normal plain old html login page where the browser save-this-password just works

19:22 noncom|2: hmmm, interesting

19:22 justin_smith: noncom|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:23 noncom|2: ok, 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:23 justin_smith: noncom|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:23 noncom|2: ah

19:23 well okay

19:24 justin_smith: noncom|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:24 that makes the auth questions in the server side much simpler

19:25 noncom|2: justin_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:27 justin_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:27 justin_smith: noncom|2: nice to know I dodged that bullet

20:04 lol http://www.foaas.com/

20:07 TEttinger: oh my god Ballmer

20:07 justin_smith: lol

20:08 TEttinger: oh that's awesome I hadn't gotten to that one yet

20:12 TEttinger: https://www.refheap.com/114550

20:13 I know that in the real world there is no such rivalry

20:16 TEttinger: nice

20:18 visof: ,(partition 2 1 [1 2 3 4 5 6])

20:18 clojurebot: ((1 2) (2 3) (3 4) (4 5) (5 6))

20:19 visof: ,(map (fn [xs] (first xs)) (partition 2 1 [1 2 3 4 5 6]))

20:19 clojurebot: (1 2 3 4 5)

20:20 justin_smith: ,(map first (partition 2 1 [1 2 3 4 5 6])) ; (fn [xs] (first xs)) is a weird way to write first

20:20 clojurebot: (1 2 3 4 5)

20:21 visof: justin_smith: yeah that's neater, but fn i'm planning to do more complex things than first

20:22 justin_smith: k

20:26 amalloy: speaking 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:26 justin_smith: so 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:26 amalloy: a poor way to write (is (every? #(f x %) ys))

20:27 justin_smith: amalloy: wow, double whammy there

20:29 (boolean (is (= true (boolean (every? true? (doall (map #(boolean (f x %)) (seq ys)))))))) ; ftw

20:30 no, justin_smith, there is no winning this game and there is always a way to add silly complexity

20:32 oh man - cljs : (inc :1) => ":11"

20:33 I mean you deserve it if you make a terrible keyword like :1, but wow that's gross

21:40 Bronsa: justin_smith: wow :/

21:54 kenrestivo: justin_smith: ugh

23:26 rhg135: that's... disturbing

Logging service provided by n01se.net