#clojure log - Dec 20 2012

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

0:06 mehwork: apt-get install clojure installed 1.1, but i want clojure 1.4. what's the best way to get it? can i just add 1.4 to my leiningen's :dependencies?

0:08 tpope: yes

0:08 don't bother with apt for anything other than maybe java itself

0:08 Raynes: Never use a package manager for anything Clojure related besides Java.

0:08 You'll wake up naked and covered in blood.

0:09 mehwork: thanks

0:10 Raynes: Leiningen is totally independant of anything else. It downloads Clojure versions as necessary and manages all the pain for you to keep you waking up clothed, or at least clean with no blood.

0:10 mehwork: it's insane not having basic string splitting functions and stuff in 1.1

0:10 Raynes: There is stuff like that in Java itself that you used in 1.1

0:10 But yeah, 1.1 is way too old.

0:10 You definitely don't want that.

0:10 mehwork: i wanna stay as far away from java as possible

0:11 Raynes: Then you might be using the wrong languag.

0:11 language*

0:11 mehwork: probably

0:11 Raynes: Everything calls out to Java somewhere. There are a lot of Clojure libraries around, but there are lots of Java libraries too, and chances are you'll find yourself wanting one eventually.

0:12 mehwork: then i'll jus wrap them

0:12 Raynes: Thought you wanted to stay away from Java? ;)

0:12 mehwork: as much as possible

0:13 Raynes: Words, words.

0:51 bbloom: when viewed with the experience of values and identities, the browser dom is completely fucking hopeless

1:13 tomoj: it's hopeless because if you build something decent on top of it, it will be too slow?

1:13 or because you just can't build anything decent on top of it

1:13 bbloom: tomoj: both. heh

1:14 i'm tempted to just write my own complete gui toolkit on canvas

1:14 apparently even mozilla is toying with that idea: https://wiki.mozilla.org/Labs/Thunderhead

1:16 Raynes: Obviously stealing your idea.

1:16 Also, my word. They need to quit with the names.

1:16 What's next? ElectricStormParakeet

1:17 brainproxy: is the datomic crew more or less moving away from the ".dtm" filename extension convention in favor of ".edn"?

1:18 tomoj: why is using canvas underneath much easier?

1:19 bbloom: tomoj: the main problem is one of shit changing under you

1:19 there are basically two approaches: play the DOM game with css/html/javascript, or own everything

1:20 angular.js plays the DOM game

1:20 cappichino or GWT owns everything

1:20 in the own everything view, you can assume the dom only changes in controlled ways

1:20 but it makes it hard for you to safely employ css, etc

1:20 or custom event handlers

1:20 or dom inspection

1:20 if somebody changes some shit in the web inspector, you're fragile little view of the world may break

1:21 if you wanted to have an immutible snapshot of the DOM state, you simply can't get it. because even simple things like event handlers aren't queryable from any dom API

1:21 there is no way to say getAllEventHandlers

1:22 the advantage of owning everything is that you can do more powerful stuff, like dynamic layouts. you just absolutely position everything via javascript

1:23 tomoj: jquery's deep clone only copies event handlers which were added by jquery, I assume

1:23 bbloom: but then at that point, you're just using the dom as a finely optimized rectangle renderer with some native widgets for text input. and you'll want to skin everything for a professional app anyway, so you might as well skip the rectangle renderer and render arbitrary lines and shit :-P

1:23 correct

1:24 also, i used to do game dev, sooo i part of me wants to say fuck it and go off and implement a compositor

1:24 that would be easier than dealing with the fucking dom :-P

1:25 Raynes: are you seriously going to go implement this?

1:26 ro_st: implement what?

1:26 bbloom: canvas gui toolkit w/ clojurescript :-)

1:26 ro_st: from scratch?

1:27 bbloom: *shrug*

1:27 ro_st: ambitious.

1:28 when it comes to rendering, you want short stacks for performance. clojurescript doesn't make for short stacks

1:28 bbloom: "short stacks" ?

1:28 ro_st: call stacks

1:28 stack as in stack overflow

1:29 bbloom: yeah, but i'm not sure what you're getting at.... call overhead? since when does the height of the stack matter for performance?

1:29 ro_st: although, i've never done anything with canvas, so i could be totally wrong.

1:30 Raynes: bbloom: Am I going to what what?

1:30 ro_st: the less stuff that happens in hot loops, the faster they go. if your logic has to work through the cljs abstractions to get at the 'raw' js in that loop, that means you're losing some performance

1:30 bbloom: Raynes: I said canvas gui, you said "Obviously stealing your idea."

1:30 ro_st: for the same reason games use c/c++ for their 3d engines instead of lua

1:31 Raynes: bbloom: No sir, I was implying Mozilla stole your idea.

1:31 bbloom: ah, heh

1:31 Raynes: I wouldn't touch that with a 10 foot career.

1:31 bbloom: haha

1:31 ro_st: -grin-

1:47 mehwork: is there a diff between (defn- main) and (defn -main) ?

1:48 tomoj: the former defines a private function called 'main, the latter a public function called '-main

1:49 mehwork: i take it it's a bad idea to do (defn- -main)

1:50 ro_st: only if you want to be able to call main from outside the ns

1:55 tomoj: event handlers seem problematic (in the don't-own-everything approach), but I don't feel like I want an immutable snapshot of the dom which includes event handlers

1:57 bbloom: tomoj: i'm not actually going to build a canvas gui :-P just venting a bit. i'm still exploring the design space, so i'm not exactly sure how to deal with it

1:58 i think the preferable approach is closer to angular.js

1:58 but i want to embrace clojure's data view of the world

1:59 currently, i have a prototype working that has a data structure, recursively expands templates and "styles", much like macro expansion, and the expanded form can be rendered to a dom

1:59 clearly rebuilding the entire dom on every update is inefficient

1:59 so i'm searching for a way to intelligently apply the delta to the dom

2:01 it seems the only valid strategy is to assume no one is going to open the web inspector and muck with your elements. and you just pray that no extension is corrupting the dom in any serious fashion

2:02 ro_st: not a valid assumption to make at all. lastpass does stuff to the dom, for example

2:02 both when rendering its noticebar and when populating fields with data

2:02 bbloom: hence the "serious fashion" qualifier

2:02 it's one thing to add a top level div

2:02 it's another thing to insert random elements and modify random properties scattered throughout the page

2:03 ro_st: true

2:03 bbloom: and when populating fields with data, a well behaved plugin would most likely trigger a value-change event

2:03 which would be more or less indistinguishable from the user typing in that field

2:05 mehwork: is it wrong to put -main in core.clj? core.clj has (ns foo.core) and my project.clj has :main foo.core but when i lein run -m src/foo/core.clj i get an error

2:05 it seems to work fie if i put the -main function in a diff file and set :main to that though

2:07 ro_st: and if you just lein run?

2:07 no -m path

2:07 tomoj: (btw it's -m ns, not -m path: `lein run -m foo.core`)

2:08 bbloom: the thing you're describing is one-way only, right? data->dom?

2:08 bbloom: tomoj: i have one-way working with complete-re-render

2:09 tomoj: my goal is full two-way

2:09 tomoj: with efficient incremental updates

2:09 my little template/styles macro expanding jazz is actually quite simple and pleasant to work with

2:09 it's roughly analogous to microsoft's WPF logical and visual trees

2:09 basically, i have some "logical tree" which is "template expanded" into a visual tree

2:10 and the visual tree is roughly a static snapshot of the target dom

2:10 so i just hiccup-ize it right now for proof of concept

2:10 works nicely

2:11 mehwork: tomoj: hmm thanks. lein run by itself worked but lein run -m foo.core still errors

2:12 tomoj: so ideally, in the data->dom case, web inspector tweaks would just be immediately undone? or a bit less ideally, next time the data changes?

2:14 bbloom: tomoj: i'm not super worried about web inspector tweaks, i just mention them as an annoyance

2:15 tomoj: in theory, they'll immediately be overwritten by a re-render for that subtree

2:15 tomoj: guess it's irrelevant since we want two-way. I don't understand what two-way would look like

2:16 bbloom: so angular works by having "directives" for each bindable thing

2:16 for example, ng-checked http://docs.angularjs.org/api/ng.directive:ngChecked

2:16 i'm thinking that i'll do something similar

2:17 something like {:tag "color" :attr/title "you see this on hover" :css/color "red" :bind/click xyz}

2:18 er tag shoulda been "div"

2:18 brain fart

2:20 tomoj: so the model is an identity and dom changes and bound to mutate it

2:20 bbloom: something like that

2:21 my goal is an order of magnitude productivity win over everything else out there :-)

2:21 it's a hobby project though... if i had to do real work starting tomorrow, i'd just suck it up and use angular + coffeescript :-P

2:34 tomoj: so you need one function to update a model given input from the dom, and one to update the dom given the model. and a binding is both functions?@

2:39 alex_baranosky: what's the current status of the Korma project? A quick look on clojars shows more than ten non-official Korma jars there

3:02 mehwork: is it bad to def a var, then on the next line def it again by apply'ing something to it? Effectively creating and manipulating the same state?

3:02 or what is the convention

3:03 ro_st: not bad. you might want to (def foo (let [foo (something)] <alter foo>))

3:04 the let binding replaces your first def

3:04 mehwork: i see, thanks

3:07 where can i read about <alter>?

3:07 ro_st: that's just me saying "do something with foo"

3:07 <alter> isn't actual clojure syntax

3:07 mehwork: oh :p

3:07 ro_st: sorry for the red herring :-)

3:07 mehwork: it's okay. I'm relieved

3:08 ro_st: (def foo (let [a 1] (inc a))) ; foo is 2

3:10 alex_baranosky: mehwork: imo that is bad form. something you only do if you absolutely must

3:11 mehwork: if you have mutable state why not use an atom or ref for it?

3:11 mehwork: do you really need this mutable state? <-- that's the real question. Usually the answer is "no".

3:12 mehwork: idk, i'm still a complete noob

3:15 ro_st: baby steps.

3:15 ebaxt: I'm having a "there

3:15 I'm having a "there's a function for that" moment, anyone? https://www.refheap.com/paste/7744

3:17 ro_st: ebaxt: looks like group-by might help

3:18 ebaxt: ro_st: I don't want a vector for each key since I know they are unique

3:35 amalloy: (into {} (for [x coll] [(:foo x) x]))?

3:35 (into {} (map (juxt :foo identity) coll))

3:36 ebaxt: ^

3:37 tomoj: my port of clojure.test to clojurescript seems to be basically working

3:38 mehwork: how do you convert all integer key values to strings in a map? eg {1:"foo", 2:"bar"} becomes {"1":"foo", "2":"bar"}?

3:38 do i need to use doseq

3:39 tomoj: (into {} (for [[k v] m] [(str k) v]))

3:39 ro_st: (into) is a great bit of kit

3:39 tomoj: I wish it were (into-kv {} (map-k str m)), but it's not

3:41 mehwork: or is there an option to do it during map-indexed hash-map seqname

3:41 it would be nice if map-indexed took a callback to filter through first

3:43 tomoj: wait, what? you're doing something like ##(map-indexed {1 :foo 2 :bar} [:baz :bing :bang :bong]) ?

3:43 lazybot: ⇒ (:baz :foo :bar :bong)

3:44 amalloy: hah. i never thought of using a map as the map-indexed function

3:44 mehwork: interesting

3:45 tomoj: or, or ##(map-indexed hash-map [:foo :bar :baz])

3:45 lazybot: ⇒ ({0 :foo} {1 :bar} {2 :baz})

3:45 ebaxt: amalloy: Thx, shorter at least ;)

3:45 tomoj: for the latter, ##(map-indexed #(hash-map (str %1) %2) [:foo :bar :baz]) :/

3:45 lazybot: ⇒ ({"0" :foo} {"1" :bar} {"2" :baz})

3:46 noidi: ,(zipmap (range) [:foo :bar :baz])

3:46 clojurebot: {2 :baz, 1 :bar, 0 :foo}

3:46 noidi: ah, that's not what you were doing

3:47 mehwork: that told me nested #()'s are not allowed when done inside a let

3:48 noidi: what's the , mean

3:50 ro_st: it tells clojurebot to execute the code

3:50 ,(inc 41)

3:50 clojurebot: 42

3:50 ro_st: ,(* 3 7 2)

3:50 clojurebot: 42

3:51 mehwork: ,(= 42)

3:51 clojurebot: true

3:51 mehwork: ,(= 42 "meaning of life")

3:51 clojurebot: false

3:53 tomoj: the double # tells lazybot to eval: ##(+ 1 2)

3:53 lazybot: ⇒ 3

3:53 tomoj: &(+ 1 2) ; (or initial &)

3:53 lazybot: ⇒ 3

3:54 mehwork: why does zipmap return the map reversed

3:55 ro_st: it's conjing onto a list, which conj's on to the beginning

3:55 vectors conj onto the end

3:56 this is for performance reasons

3:56 not because it's sensible -grin-

3:56 mehwork: is that to do with lazy sequencing

3:56 ro_st: ,(conj (list 1 2) 3)

3:56 clojurebot: (3 1 2)

3:56 tomoj: &(-> {} (assoc 1 2) (assoc 3 4) (assoc 5 6))

3:56 lazybot: ⇒ {5 6, 3 4, 1 2}

3:56 tomoj: no list in zipmap

3:56 ro_st: ,(conj [1 2] 3)

3:56 clojurebot: [1 2 3]

3:57 ro_st: oh. then it's something else. but what i showed about conj and lists/vectors is still good to know

3:58 clgv: what's the question?

3:58 tomoj: &(zipmap (take 9 (range)) (range))

3:58 lazybot: ⇒ {8 8, 7 7, 6 6, 5 5, 4 4, 3 3, 2 2, 1 1, 0 0}

3:58 tomoj: &(zipmap (take 10 (range)) (range))

3:58 lazybot: ⇒ {0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7, 8 8, 9 9}

3:58 mehwork: yeah the docs for conj say they may be in different places depending on the concrete type

3:58 clgv: mehwork: that's what the scala people did not like as well ;)

4:01 tomoj: is there any hope for denotational semantics in clojure - not for proofs, just for design aid

4:04 clgv: tomoj: I think `conj` is the worst example and to a certain degree the querying and delting operations associated with it on sequential data.

4:05 ,(peek '(1 2 3))

4:05 clojurebot: 1

4:05 clgv: ,(peek [1 2 3])

4:05 clojurebot: 3

4:07 tomoj: do the semantic types include lists and vectors?

4:07 IReduce?

4:08 I guess I should read about semantics

4:10 mehwork: how do you sort a map by it's numerical keys? i tried (into (sorted-map) mymap) but it's coming out disordered

4:11 ro_st: ,(into (sorted-map) {3 2 1 6 4 5})

4:11 clojurebot: {1 6, 3 2, 4 5}

4:11 clgv: mehwork: `sorted-map-by` let's you provide a comparator

4:12 ro_st: keys look sorted to me

4:13 tomoj: &(keys (zipmap (range 20) (range)))

4:13 lazybot: ⇒ (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)

4:13 tomoj: coincidence!

4:14 I misread as "#'keys looks sorted to me"

4:14 clgv: ,(let [kvs (repeatedly 20 #(rand-int 100))] (println "kvs =" kvs "\nsorted-map =" (apply sorted-map kvs)))

4:14 clojurebot: kvs = (57 76 0 89 53 ...)

4:14 sorted-map = {0 89, 38 16, 42 15, 48 27, 49 16, ...}

4:15 clgv: &(let [kvs (repeatedly 20 #(rand-int 100))] (println "kvs =" kvs "\nsorted-map =" (apply sorted-map kvs)))

4:15 lazybot: ⇒ kvs = (48 42 74 4 15 98 80 75 69 97 96 87 27 75 23 35 43 20 59 98) sorted-map = {15 98, 23 35, 27 75, 43 20, 48 42, 59 98, 69 97, 74 4, 80 75, 96 87} nil

4:15 alex_baranosky: is Korma compatible with Clojure 1.2.1?

4:16 clgv: alex_baranosky: you should put in the effort to upgrade. I've been sitting on 1.2.1 until 2-3 months ago. it's a pain when all the libs move on and you cant use a decent number of them anymore

4:17 &(let [kvs (repeatedly 20 #(rand-int 100))] (println "kvs =" kvs "\nsorted-map =" (seq (apply sorted-map kvs))))

4:17 lazybot: ⇒ kvs = (9 2 32 84 86 5 34 7 63 9 66 47 97 86 62 71 19 68 82 33) sorted-map = ([9 2] [19 68] [32 84] [34 7] [62 71] [63 9] [66 47] [82 33] [86 5] [97 86]) nil

4:17 mehwork: ah sorted-map-by is what i needed cause now it's the values i need

4:19 alex_baranosky: cigv: in due time, but for the time being I am trying to fix a issue at work, by moving some old code off clj-record

4:20 I can do that faster than I can do a move to 1.4

4:55 clgv: alex_baranosky: guess you have to try korma with 1.2.1 to get an answer. a profile for clojure 1.2.1 in the project.clj would be a good sign for you

5:12 Raynes: alex_baranosky: Clojure 1.2.1 lolnoob

5:16 ejackson: Raynes: Now I know why you live out in the sticks - to avoid all the slaps !

5:16 Raynes: ejackson: Yeah, but that's only until February. Then I'll be in slapping distance of everyone I insult on the west coast.

5:17 * ro_st is going to have a go at talking at ClojureWest

5:18 ro_st: will me nattering on about how we've used Clojure end-to-end be interesting enough?

5:18 ejackson: I'll get you a gumguard for Christmas

5:18 ro_st: experience reports are always super interesting.

5:18 Raynes: ejackson: Sweet

5:18 ro_st: what sort of details would be of value?

5:19 ejackson: edges, corners, when you had to do something ugly

5:19 ro_st: we're only launching on the 14th of jan, but by the time of the talk, we should be several thousand users strong

5:19 * ejackson is strongly resisting the pull to submit a call... no time for jamborees !

5:20 ro_st: we are using values-based programming end to end.

5:20 using event sourcing for the main app's persistent data model

5:20 datomic, clj, cljs, pallet

5:21 i think there's probably enough meat in there

5:21 ejackson: yeah, people always like to hear about somebody actually winning !

5:22 ro_st: that's true

5:55 piranha_: ro_st: do you do in-browser app, or what is it in the end?

5:55 ro_st: it's a webapp, yes

5:55 html5 multi-platform

5:55 deskop/tablet for now. dedicated mobile ui sometime next year

5:56 piranha: aha, how do you do user interface? FRP?

5:56 ro_st: i'd love to get there. we probably have a half-baked FRP hiding in amongst our code

5:56 piranha: I see...

5:56 Raynes: Translation to human speak is: "it's all broke"

5:56 ro_st: we use shoreleave's remotes and pubsub along with enfocus for templating and event handling

5:57 piranha: I'm trying to get in by using Flapjax, so far it's... well, works somehow for simple things, not sure if it will be good for big stuff

5:57 I see

5:57 ejackson: Raynes: maybe a helmet, actually...

5:57 piranha: ro_st: how do you handle data on the client? :) Atoms? Or inside of the DOM? :)

5:57 ro_st: atoms

5:58 but all the atoms are in one namespace; all the actual logic is pure

5:58 on the client, the cljs uses the atom namespace as a singleton; on the server, i use binding to scope those atoms when working with the data

5:58 we use lein-cljsbuild's crossovers to share the model code in clj/cljs

5:58 piranha: aha... I wrote my own abstraction for managing data in atoms, and I would love to hear some feedback (if I'm crazy or not, haha), clojure mailing list is keeping silence :))

5:59 ah, I see... I plan to write only browser part in clojure

6:00 ro_st: the atoms only hold transient data only; the persisted data is event sourced. so loading a document merely replays events into a running session and that reconstitutes the state

6:00 never persist and repopulate atoms directly

6:00 makes undo/redo dead easy to do.

6:01 mind sharing a link to your post?

6:01 Raynes: we're using the some things that FRP uses, like pubsub

6:02 Raynes: I wasn't the one who asked about FRP, but thanks for letting me know. ;)

6:02 ro_st: but by no means are we actually doing FRP. would love to spike out an FRP solution to properly understand it, but there's only so much damn time available.

6:03 ah, i was responding to your 'it's all broke' comment :-)

6:03 piranha: atoms + shoreleave-pubsub works really well

6:04 piranha: ro_st: https://groups.google.com/forum/#!topic/clojure/shkr_3AD3UM

6:04 ro_st: what means 'event sourcing'? I feel I don't really understand that :)

6:04 ro_st: ah, i've seen this. it's queued in my list

6:05 piranha: ah :)

6:05 ro_st: http://martinfowler.com/eaaDev/EventSourcing.html

6:05 piranha: thanks

6:06 ro_st: essentially, instead of transfering the full state, instead just transfer the user's actions, and re-constitute the full state by 'replaying' those actions in order

6:07 stock markets are event sourced

6:07 piranha: I see...

6:07 hmmm, interesting

6:08 ro_st: why i love it is because we get undo/redo almost for free, and when we add websockets as a transport and start to do collaborative document stuff, all i need to do is add a bit of control flow logic and rewire pubsubs

6:08 to have eg a websocket play events into a cljs workspace rather than keyboard/mouse events

6:10 and we also have instant save/resume for mobile - no big state to upload. users just use the app and the rest happens like magic

6:11 piranha: indeed, sounds nice :)

6:12 ro_st: piranha: check shoreleave-pubsub. working demo code here: https://github.com/robert-stuttaford/demo-enfocus-pubsub-remote

6:12 piranha: ro_st: thanks! I will

6:13 reading about event sourcing now :)

7:29 ro_st: anyone connecting to nrepl servers via ssh?

7:30 ambrosebs: can anyone think of a statically typed language that has keywords that are also functions?

7:30 or similar

7:36 ro_st: i don't know. that guy who did Typed Clojure seems like someone to ask, though

7:36 -grin-

7:36 llasram: ambrosebs: Keywords in the syntactic sense, or in the Clojure sense?

7:38 clgv: ro_st: roflmao!

7:39 ambrosebs: llasram: (:a coll) looks up :a in its argument.

7:39 ro_st: cemerick_: thank you, thank you, thank you for nrepl

7:39 ambrosebs: I'll scratching my head how to make that not hacky

7:39 *I'm

7:40 llasram: Oh. Hmm. Yeah -- the name defines what the value does. That is kind of weird when you think about it

7:42 ambrosebs: One idea I had was to parameterise Keyword with the key it looks up. :a is of (Keyword :a). But that has other issues.

7:42 clojurebot: Alles klar

7:42 cemerick: ro_st: :-) Anything in particular about it you're enjoying?

7:43 ambrosebs: I'm trying to get rid of my intersection type, but it comes in quite handy here. :a is just (I (Value :a) (All [x] [(U Any '{:a x}) -> (U x nil)]))

7:44 ro_st: datomic licenses by jvm process. starting up a repl consumes one process. when your production stack is already using all 3 available processes makes starting a repl impossible. but embedding nrepl server makes that unhappiness melt away :-)

7:45 ...processes, that makes*

7:47 ambrosebs: The definition of Keyword in CLJS gives a hint.

7:47 We definitely need to abstract over its "k" field.

7:48 renderful: nice repl tip ro_st, that will come in handy one day

7:49 ro_st: also a lot saner when it comes to server ram

7:49 makes me wonder why we've been hobbling along without nrepl embedded for so long

7:51 cemerick: are you attending clojurewest?

7:52 cemerick: well, other REPL servers were certainly embeddable in the past, though perhaps not as frequently as nREPL is

7:52 ro_st: probably

7:52 ro_st: buy you a beer.

7:52 cemerick: heh, thanks

7:53 hopefully Alex looks favorably on my talk submission.

7:54 clgv: cemerick: as clojure book writer you have no "auto accept status" on clojure conferencs? ;)

7:54 cemerick: heh, no

7:55 At this rate, all confs would be full-up with speakers without any submissions.

7:55 It'd get a little boring. :-P

8:05 clgv: :D

8:15 squidz: where else can I find clojure videos besides the new clojure youtube channel?

8:19 ro_st: search vimeo for clojure

8:19 search infoq.com for clojure

8:20 squidz: ro_st: okay so vimeo and infoq have a lot of clojure videos, thanks, anything else

8:20 ro_st: http://skillsmatter.com/

8:21 squidz: cool thanks

8:21 ro_st: plenty on those 3 for you

8:21 90% of em, i'd say

8:21 squidz: yeah i think so, thanks

8:22 ro_st: sure thing

8:24 squidz: i'm almost done with Joy of Clojure, and am confident I can hack some clojure, but am kind of stuck on what I should actually program. I guess the opportunity will present itself at one point or another, but I can't wait

8:26 ro_st: what's your background?

8:26 squidz: I am working as a java dev developing a facebook app for career networking

8:27 backend stuff mostly

8:27 ro_st: oh then you must be loving clojure

8:27 java devs love it once they invest enough time checking it out

8:27 squidz: yes so far i can't get enough of it. I took a detour and learned a little haskell but got frustrated with it so decided to check out clojure. I havent looked back

8:29 here is our app https://apps.facebook.com/emplido/

8:33 so far I was only able to really do one thing with clojure, and that is, sneak in a small clojure script into our project for maven to execute

8:43 ro_st: this looks ideal for clojure

8:43 squidz: really? why?

8:43 ro_st: it's well suited to the sort of data munging you're likely doing

8:44 squidz: ah I see. I guess the problem is as usual, how to convince others who know nothing of clojure

8:45 ro_st: users create data > data is collated to create information > information is queried for ratings and fuzzy matching > outbound messaging & report displays

8:45 watch the talk from Amit at Zolodeck

8:45 it's on infoq

8:45 he uses clj + storm + datomic to great effect

8:47 squidz: ill check it out. What is storm btw?

8:47 ro_st: storm-project.net

8:47 distributed real-time computation

8:47 shit-hot.

8:48 squidz: looks cool, but isn't datomic proprietary?

8:48 ro_st: it is

8:48 expensive, too

8:48 squidz: hm that makes it hard, but Ill check out the video anyways. Looks like it's interesting to learn

8:48 ro_st: still, its net effect is a radically lower cost of ownership for us

8:49 far less developer time involved, and far less code

8:49 squidz: what did you use before?

8:50 ro_st: v1 stack is php+mysql

8:50 v2 clj+datomic

8:50 squidz: oh okay, yes that must be much better

8:51 ro_st: way, WAY better :-)

8:51 squidz: ive never done anything with php, and I don't really want to

8:51 ro_st: don't

8:52 it's horrible

8:52 squidz: I guess i'll just keep checkout out clojure videos until I get an idea of a miniproject. Small steps

8:52 AdmiralBumbleBee: php isn't that bad

8:52 ro_st: yeah. do you have clojurebook.com?

8:52 AdmiralBumbleBee: people just do awful things with it

8:53 squidz: ro_st: ive seen clojurebook.com, but I havent read any of it

8:53 ro_st: great book. highly recommended.

8:54 squidz: okay, i'm almost done with Joy of clojure. Maybe checking that out afterwards will be good

8:55 maybe starting from the practicums section, since the first part of the book may be a little repetitive

8:56 ro_st: yeah

8:56 i'm going over the book again this holida

8:56 haven't used it since the solid two weeks i spent reading it before i started coding

8:57 squidz: have you made any projects on github yet?

8:57 ro_st: yup http://github.com/cognician

8:57 https://github.com/Cognician/fusebox is the most recent

8:59 squidz: cool

8:59 cemerick: ro_st: fusebox looks promising :-)

8:59 ro_st: thanks. i had a look around for a flags system in clj but found zip.

8:59 i've got a nice little addon for datomic as well

9:00 which defines an entity for the whole system, and then allows you to enable for particular entities or enums - for example, on user roles

9:00 still need to tidy it up and release it

9:01 there's almost no code to it

9:02 we had 4 different projects doing the master/develop git branch thing and it was getting seriously tedious to manage versioning and dependencies between them

9:02 so now we're just on master, and new stuff is wrapped inside fuse checks

9:03 WokenFury: cemerick: which is the best release of tools.nrepl for embedding? 0.2.0-RC1 or 0.2.0-beta9?

9:03 getting this error in RC1: java.lang.IllegalArgumentException: Multiple methods in multimethod 'print-method' match dispatch value: class clojure.tools.nrepl.server.Server -> interface clojure.lang.IDeref and interface clojure.lang.IRecord, and neither is preferred

9:03 squidz: what is the need for fuses though? To have global flags?

9:03 ro_st: fuses happen to look precisely like datomic attribute names, which isn't a coindcidence :-)

9:03 squidz: http://stackoverflow.com/questions/7707383/what-is-a-feature-flag

9:04 cemerick: WokenFury: later is better

9:04 Interesting re: the print error. I suppose I've never tried println'ing a server reference.

9:04 squidz: ro_st: ah i see

9:05 WokenFury: cemerick: afaik neither am I, just using (nrepl/start-server :port config/NREPL-PORT)

9:05 ro_st: we have one set of flags powering our web server, our background worker, and our cljs app

9:05 WokenFury: possibly because it's the last call in my main fn

9:05 ro_st: squidz: http://blog.asana.com/2011/04/using-flags-to-ease-new-feature-development/ is a great intro

9:06 cemerick: WokenFury: yeah, it's implicit if that's the last thing evaluated in e.g. a loaded file

9:06 WokenFury: aha. must've been that. sorted now

9:07 with beta9 it was spitting this out in console: #<Agent$Closeable$b14108b6@1ae57e12: {:ss #<ServerSocket ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=9991]>, :transport #<transport$bencode clojure.tools.nrepl.transport$bencode@706cac3b>, :greeting nil, :handler #<middleware$wrap_conj_descriptor$fn__8737 clojure.tools.nrepl.middleware$wrap_conj_descriptor$fn__8737@2d6f4087>}>

9:07 cemerick: Yeah, that's to be expected.

9:07 RC1 is certainly better

9:07 WokenFury: would you mind filing a bug @ http://dev.clojure.org/jira/browse/NREPL for the printing issue?

9:07 WokenFury: will do

9:11 acron^: Please excuse my ignorance, as I come from C/C++ so my mental model of operations in Clojure is lagging behind somewhat

9:11 I want to take a map and perform an operation on the value of each element in that map, depending on what they key is

9:11 I also don't want to keep fetching the map from the db

9:12 where would I even begin this, in the context of FP?

9:12 a massive 'do' function?

9:12 case?

9:13 Ember-: acron^: list comprehension?

9:14 acron^: do you have an example Ember-?

9:14 Ember-: acron^: http://clojuredocs.org/clojure_core/clojure.core/for

9:15 and yes, you can pass a map to for

9:15 and no, for is NOT a for loop

9:15 in case of a map you are effectively processing key/value pairs

9:16 acron^: hmmm

9:16 Ember-: but it might not be an optimal solution for you, clojure has some much power in map and list processing

9:16 some = so

9:16 (what I was thinking when typed _some_ ??)

9:17 llasram: acron^: By "perform operation" do you mean "perform action for side-effects" or "generate a new value, assembling the sequence of new values into a new collection"?

9:17 Ember-: list comprehension is maybe one of the hardest things to graps coming from an imperative world

9:17 acron^: llasram, the latter

9:18 tpope: I still haven't grasped it

9:18 Ember-: in that case list comprehension should be your tool

9:18 llasram: Ok, then like Ember- is saying, the `for` comprehension will do it. Although IMHO you get more milage from the composable sequence operations

9:18 acron^: lets imagine i have {:a 1 :b 2 :c 3} - I want :a to be doubled, :b to be halved and :c should be trippled

9:19 llasram: Oh!

9:19 Well that's differest

9:19 noidi: (for [[k v] my-map] (make-new-value k v))

9:19 Ember-: and yeah, I'd propably use some higher level functions

9:19 acron^: and i want the results in a new map using the original keys

9:19 llasram: So you want a different function applied to the value for each key?

9:19 Ember-: for comprehension is kinda like the ultimate low level swiss tool for stuff like that :)

9:19 noidi: where make-new-value is a multimethod with implementations for :a :b and :c

9:19 acron^: llasram: yes

9:20 so {:a 1 :b 2 :c 3} -> {:a 2 :b 1 :c 9}

9:21 Ember-: what noidi said

9:21 for comprehension + multimethod

9:22 but how many different keys do you have?

9:22 <10 or more?

9:22 acron^: potentially, yes

9:22 10-20

9:22 Ember-: ok, are they of what type?

9:23 and what kind of operations?

9:23 are they totally different from each other?

9:23 acron^: it's string in, map out

9:23 for all

9:24 llasram: acron^: ##(let [update-by-key (fn [fs m] (merge-with #(%1 %2) fs m)), fns {:a #(* 2 %), :b #(* 0.5 %), :c #(* 3 %)}] (update-by-key fns {:a 1, :b 2, :c 3}))

9:24 lazybot: ⇒ {:a 2, :b 1.0, :c 9}

9:24 Ember-: yes, but can your keys be eg. "a", 1, true and so on?

9:24 llasram: But this isn't honestly a typical solt of thing

9:24 sort even

9:24 What's your higher-level goal with this operation?

9:24 acron^: Ember-: keys are all str

9:25 llasram: i'm turning url paramters into monger queries

9:25 Ember-: hmm, sounds a bit hazardous maybe

9:25 but I gotta run

9:26 significant other called, time to meet her :)

9:26 acron^: so color=Blue,Red --> {$or [{:color "Blue"} {:color "Red"}]}

9:27 so color=Blue+Red --> {$and [{:color "Blue"} {:color "Red"}]}

9:27 etc

9:29 noidi: acron^, https://www.refheap.com/paste/7745

9:29 llasram: Interesting. I agree with noidi the multimethod approach is probably the way to go

9:29 You can provide a :default for giving things a default treatment

9:30 acron^: noidi, this is really helpful, thank you

9:31 squidz: noidi: me likey

9:34 noidi: ,(seq {:a 1, :b 2, :c 3})

9:34 clojurebot: ([:a 1] [:c 3] [:b 2])

9:34 noidi: so a sequential view of a map is a seq of map entries

9:34 ,(class (first {:a 1, :b 2, :c 3}))

9:34 clojurebot: clojure.lang.MapEntry

9:35 noidi: you can add map entries to a map with conj

9:35 ,(conj {:a 1} [b 2])

9:35 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: b in this context, compiling:(NO_SOURCE_PATH:0)>

9:35 noidi: ,(conj {:a 1} [:b 2])

9:35 clojurebot: {:b 2, :a 1}

9:36 noidi: and "into" just conj's everything in its second argument (a sequence) into its first argument

9:36 so then there are only multimethods, which are too complex to be explained on IRC :)

9:37 acron^: :E

9:39 squidz: acron^: have you done anything with multimethods yet?

9:39 acron^: Nothing at all

9:39 reading up now

9:40 squidz: nows a better time than ever I guess

9:42 acron^: noidi does "map" internall cally seq on the passed in map then?

9:43 noidi: acron^, yes

9:43 acron^: gotcha

9:45 tbaldridge: almost every sequence function calls seq on its argument. Vectors are not seqs, so map wouldn't work with vectors otherwise.

9:47 mmitchell: weavejester: Quick question about Compojure... is it possible to dispatch on a query param and its value?

9:49 weavejester: i currently have 1 route to a controller. The logic in the controller is very complicated due to some wacky business logic around a single query param. I'd love to be able to completely separate the logic into 2 controllers using routes.

9:55 clgv: mmitchell: you just can dispatch the clojure function in the route depending on the query param

9:57 (GET "/myrout" request (dispatch request)) and (defn dispatch [{{:keys [myparam]} :query-params :as request] (if (= myparam "awesome) (awesome-fn request) (default-fn request))

9:59 mmitchell: clgv: very cool thanks!

10:08 yedi: is there like a protocol or spec or format or something that can be used for storing/sending boolean rules (combinations of logical statements)

10:09 weavejester: mmitchell: You could also write it a little more concisely - there's usually no need to pass the whole request out

10:09 mmitchell: (GET "/foo" [p] (case p "foo" foo-route bar-route))

10:09 mmitchell: weavejester: you mean by passing only the :query-params?

10:09 ahh ok

10:10 weavejester: mmitchell: You can return another handler from a route

10:10 mmitchell: nice

10:23 ppppaul: anyone have suggestions for testing my ring?

10:24 i see there is a lib ring-mock... it good?

10:24 clojurebot: libraries is http://clojure.org/libraries

10:24 weavejester: ppppaul: There's some other systems built on top of ring-mock

10:25 ppppaul: Let me see if I can find the name of the one I'm thinking of

10:25 ppppaul: i'm also interested in mocking out http calls (my server is talking to other servers, and right now i'm in a hairy place where i could really use some testing fast)

10:25 squidz: does anybody do a blog in clojure?

10:26 nathanic: squidz: this blog http://yogthos.net/ is written in clojure. src: https://github.com/yogthos/yuggoth

10:27 it even supports .war deployment in an application server, which is nice for people with JEE day jobs like me

10:27 weavejester: ppppaul: Try looking at https://github.com/xeqi/kerodon

10:28 squidz: nathanic: thanks

10:28 weavejester: ppppaul: if you're testing a web app

10:28 ppppaul: Or https://github.com/xeqi/peridot

10:28 ppppaul: if you're testing a web service

10:29 ppppaul: i'm building an api

10:29 peridot looks sexy

10:30 kerodon looks like magic *_*

10:30 thanks weavejester

10:30 :D

10:33 i have another issue. i'm using ring via 'lein ring server-headless' and i would like to see my logs going to the console. i am having trouble doing this. it seems like my logs are going into some void

10:37 jweiss: how would one generate a keyword in the current namespace (without explicitly mentioning the namespace). i tried *ns* but that didn't work at runtime, *ns* value ended up being clojure.core.

10:38 i mean, create it from a string

10:38 ,(keyword "::foo")

10:38 clojurebot: :::foo

10:38 jweiss: doesnt work

10:38 ,(keyword "foo" (-> *ns* .name name))

10:38 clojurebot: :foo/sandbox

10:41 dhm: jweiss: (intern *ns* (symbol (str (keyword "foo"))))

10:42 llasram: jweiss: Extracting from `*ns*` should in fact work... Are you sure you didn't have scoping issues?

10:43 &(keyword (-> *ns* ns-name name) "foo")

10:43 lazybot: ⇒ :sandbox7657/foo

10:44 jweiss: llasram: eg, (defn mkkey [] (keyword (-> *ns* ns-name name))) did not work

10:44 was returning clojure.core, not the namespace in which mkkey was defined.

10:44 sorry left out the string part of the keyword but you get the idea

10:45 llasram: Oh! *ns* is dynamic, so you'll get the value of *ns* where mkkey is called

10:46 jweiss: llasram: yeah, so i was trying to figure out how to refer to the current ns, meaning at compile time

10:46 llasram: (let [kw-ns (-> *ns* ns-name name)] (defn mkkey [s] (keyword kw-ns s))

10:46 )

10:46 :-)

10:47 jweiss: just trying to avoid a gotcha where i refactor the name of the namespace and inadvertently introduce a mismatch if i forget to update the hardcoded name

10:48 llasram: Right. So like I have above, you capture the ns name string in the lexical scope of the function. When you re-compile the namespace, the forms get re-evaluated, so renames follow automatically

10:48 jweiss: llasram: ok thanks

10:49 ppppaul: i'm trying to do interactive ring dev via emacs. i have :dev-dependencies [[ring-serve "0.1.1"]] in my project however i'm not getting 'ring.util.serve on my classpath. any ideas?

10:49 reading docs form this url https://github.com/mmcgrana/ring/wiki/Interactive-Development

10:49 llasram: ppppaul: Are you using Leiningen 1?

10:49 ppppaul: 2

10:50 llasram: Then :dev-dependencies -> :profiles {:dev {:dependencies [...]}}

10:50 ppppaul: interesting

10:50 i'll do that no

10:50 w

10:51 llasram: I *think* you probably want ring-server instead of ring-serve though. It's more recent, and doesn't depend on an ancient version of hiccup

10:51 (I don't do much webdev so I can't say definitively, but that's what I found when I was doing a tiny compojure app last week)

10:52 weavejester: ring-serve is out of date, but I haven't got around to adding support for emacs debugging into ring-server

10:52 llasram: Ah

10:52 weavejester: But the emacs debugging landscape for Clojure has changed a lot since then

10:52 nrepl seems to be the future

10:53 llasram: Yeah -- what does "support for emacs debugging" mean exactly?

10:54 Oh, swank.core/break

11:02 ppppaul: llasram, the :profiles goes in my project.clj or it goes in .lein/profiles ?

11:04 llasram: ppppaul: project.clj

11:20 ppppaul: i started clojure with swank a few years ago. now i'm back into clojure and i see that i'm being told to use nrepl. can someone explain why?

11:21 drewr: ppppaul: no one in the clojure community supporting swank-clojure coupled with nrepl being actively developed

11:21 ppppaul: is there a big difference right now?

11:22 drewr: little things mainly; I still use swank-clojure

11:23 ppppaul: so i have the same commands in emacs when i use it?

11:24 nDuff: They're not exactly equivalent, no.

11:25 ppppaul: i have ring.util.serve on my classpath now, but when i try (use 'ring.util.serve) i get an error

11:25 classnotfoundexception :(

11:29 drewr: ppppaul: no, the bindings are slightly different and the functionality is somewhat divergent; eventually I expect the nrepl interaction to be vastly superior though

11:29 ppppaul: drewr, the nrepl looks interesting

11:30 right now my problem is getting ring working in emacs

11:30 :(

11:34 any help with this would be appreciated... the ring docs for this are painfully incorrect :(

11:34 weavejester: Which docs?

11:34 ppppaul: https://github.com/mmcgrana/ring/wiki/Interactive-Development

11:35 i do this -> user> (use 'ring.util.serve)

11:35 i get back classnotfoundexception

11:35 weavejester: ppppaul: That's an out-of-date repository you've linked to

11:35 ppppaul: https://github.com/ring-clojure/ring/wiki/Interactive-Development

11:35 ppppaul: when i do lein classpath | grep serve i find the class

11:35 uuuuuuuuuuugggggggggggg!

11:35 :(

11:36 weavejester: ppppaul: But the ring-serve instructions are still the same

11:36 ppppaul: lol

11:36 weavejester: What happens when you (use 'ring.util.serve)

11:36 ?

11:36 ppppaul: oh cool, you made it the lib

11:37 weavejester, pm

11:39 weavejester: ppppaul: It might be that ring-serve doesn't work with Jetty 7, which is used by the latest versions of Ring.

11:39 ring-serve is an out-of-date library

11:40 You might want to try using the Ring adapter instead

11:40 Or just using lein-ring

11:41 ppppaul: ok, i didn't know about the alternatives

11:41 so long as swank/break works i'm happy

11:41 or if logging works

11:41 or anything to help me debug

11:42 weavejester: Logging will work with lein-ring or the standard adapter

11:42 ppppaul: logging via (print/pprint)/?

11:42 weavejester: I don't think anything works with swank/break. I'll need to find some time to look into the newer Clojure debugging tools

11:43 swank seems to be being deprecated for Clojure in favor of nREPL

11:43 ppppaul: Yep

11:45 ppppaul: hmm, it doesn't seem to be working for me

11:45 maybe i'm looking in the wrong place

11:46 weavejester: ppppaul: What's not working?

11:46 ppppaul: my print statements aren't making it to the console

11:46 weavejester: ppppaul: Which console? A normal terminal? Emacs swank? Emacs nREPL?

11:48 ppppaul: terminal

11:49 i couldn't get ring working in emacs

11:49 i'm using lein ring server-headless

11:49 however, my code is currently throwing stack traces

11:49 it would be awesome to be able to have breakpoints working on my server

11:50 weavejester: ppppaul: You might want to look into Ritz

11:51 ppppaul: looking

11:52 weavejester: But to be honest I haven't found breakpoints to be useful enough to bother with

11:52 ppppaul: :)

11:52 weavejester: At some point I'll probably try Ritz

11:52 But

11:52 If your application consists of many small, pure functions, you can try out all parts in a REPL anyway

11:53 ppppaul: my app is a bit hairy now. just started putting in tests

11:56 tomoj: hmm https://www.refheap.com/paste/1f9f6acaced723eff69ce1e4f

11:56 clojurescript

11:56 llasram: I really want to just sit and watch someone who uses breakpoints in their workflow, so I can understand when they may be useful

11:57 tomoj: seems you can't expand to a try/catch with a js/* for the class?

11:58 weird thing is that analyzing the output of cljs.analyzer/macroexpand-1 works fine

12:01 dnolen: https://www.refheap.com/paste/1f9f6acaced723eff69ce1e4f

12:02 (ana/analyze env (ana/macroexpand-1 env '(defcatch foo [] bar))) works fine

12:02 but (ana/analyze env '(defcatch foo [] bar)) throws that error

12:03 bug?

12:03 clojurebot: Paste the contents of project.clj and ~/.lein/init.clj along with the output of ls ~/.lein/plugins and lein version.

12:03 S11001001: llasram: I used them occasionally in Common Lisp, but never bothered in Clojure.

12:03 Of course, SLIME's CL support for breakpoints and inspecting stacktraces is pretty spectacularly good

12:05 llasram: I'd say FP makes them much less useful.

12:06 llasram: S11001001: I definitely used them in C, so maybe that's it

12:09 tomoj: hmm, now (ana/analyze env (ana/macroexpand-1 env '(defcatch foo [] bar))) has the same error

12:10 but if I take the output of (ana/macroexpand-1 env '(defcatch foo [] bar)) and copy it to (ana/analyze env HERE), it works

12:10 O_o

12:11 dnolen: tomoj: hmm no idea.

12:11 tomoj: it looks like it thinks the name that holds the exception is js/Error

12:11 ppppaul: can anyone help me get lein to run my tests on file changes?

12:11 i would like to have a setup similar to testacular (JS) but for my clojure project

12:12 tomoj: when the error happens, the try* form is (try* bar (catch js/Error e__8915__auto__ 42))

12:12 dnolen: tomoj: yes that try* is wrong

12:13 tomoj: yeah, but if I macroexpand-1, it's (clojure.core/defn foo [] (try bar (catch js/Error e__8915__auto__ 42))). hmmm

12:14 dnolen: tomoj: and you're calling ana/macroexpand-1 ?

12:14 tomoj: yeah

12:15 dnolen: tomoj: it looks like somehow you're macroexpanding Clojure try and not CLJS try

12:16 tomoj: try is a special form in clojure, isn't it?

12:16 dnolen: tomoj: it is, but it's a macro in CLJS that expands to a try*

12:19 antoineB: how do you not enforce immutability in cljs? (dealing with gui stuff)

12:19 dnolen: antoineB: ?

12:21 antoineB: i use set! to do for exemple cross reference with a dom element and my type

12:22 maybe you have some project with good design?

12:22 tomoj: aha

12:22 dnolen: antoineB: still not sure what you are asking.

12:23 antoineB: it's a bit unclear for me

12:24 tomoj: https://github.com/clojure/clojurescript/blob/ebe40c8a/src/clj/cljs/core.clj#L866

12:24 the try macro checks for list?

12:24 should it be seq? ?

12:24 antoineB: something like that http://en.wikipedia.org/wiki/Functional_reactive_programming

12:27 tomoj: you will write "(catch " not "[catch " so i think i will be a list

12:28 tomoj: &(list? `(catch foo))

12:28 lazybot: java.lang.SecurityException: You tripped the alarm! catch is bad!

12:28 tomoj: well, it's false

12:28 but that's probably not the exact reason why

12:30 dnolen: tomoj: yeah that definitely looks like the problem.

12:31 tomoj: I expected to find seqs in there, but looks like it is just the conses

12:33 dnolen: tomoj: if you can confirm that fixes it for you, I can commit that change here.

12:33 tomoj: yep, that fixes it

12:33 at least, on my stupid test case

12:34 by the way, I'm porting clojure.test to cljs.test by keeping the ns/var->test mapping in atoms cljs-side. will an official port have to wait until vars are reified?

12:35 dnolen: tomoj: fixed in master

12:35 tomoj: confirmed that that fixed my real case, (is (thrown? js/Error ...))

12:37 dnolen: tomoj: I see no reason to wait for that. run-tests can be a macro that uses the atom to generate all the test calls.

12:37 tomoj: a port of clojure.test would be most welcome.

12:38 tomoj: I had run-tests as a macro

12:38 and all the rest

12:38 with the mapping clj side. but that seemed to break when using the repl

12:39 now run-tests is a function that accepts symbols and looks them up in the atoms (cljs side)

12:40 which incidentally means you can deftest in the repl, although I didn't really want that much

12:41 I had to change the namespace to cljs.test, which breaks tradition, because there are macros

12:42 could stay with clojure.test and have a clojure.test-macros or something

12:45 technomancy: llasram: the one time I found stepping through breakpoints to be really useful was when I was investigating a bug in Clojure itself

12:47 dnolen: tomoj: I think cljs.test makes the most sense. I think the only reason there are namespaces like clojure.string is because of the old namespace clobbered by locals bug.

12:48 tomoj: well I guess the argument for clojure.test is that feature expression might arrive one day, and that's one less hassle. that's a big argument for clojure.test actually.

12:49 technomancy: aha; it was a bug where you could read a form containing an invalid map in clojure 1.2 and it wouldn't throw an exception until you tried to access the map

12:49 that was a fun one

12:50 konr_trab: Any idea why lein [ring] would not generate the uberwar, keeping the generation process going on indefinitely?

12:51 weavejester: konr_trab: When a compile process goes on indefinitely that's usually an indication there's some loop outside of a function

12:52 konr_trab: e.g. if I tried to compile (def foo (doall (repeat 1)))

12:52 hugod: le

12:55 konr_trab: weavejester: thank you! That was exactly the case!

12:56 mmitchell: anyone here using sublime text w/nrepl?

12:56 tomoj: dnolen: but that would mean putting the clojurescript parts of clojure.test in clojure.git?

12:57 technomancy: mmitchell: pretty sure it can't do that yet

12:57 mmitchell: technomancy: yeah seems so

12:58 dnolen: tomoj: really? I think I'm missing something here.

12:59 llasram: technomancy: Oh, wow. Yeah, I could see any tool you could weild being useful against that one

12:59 tomoj: would feature expressions let you define macros in clojurescript/.../clojure/test.cljs ?

13:00 llasram: I really need to fix erc-spelling-mode not working until I turn it off then back on...

13:00 technomancy: llasram: typically it's most valuable in worst-case-scenarios though

13:00 tomoj: otherwise you have to put them in clojurescript/.../clojure/test.clj

13:00 which is.. taken

13:00 the alternative I see is to have clojure/.../clojure/test.clj use feature expressions

13:01 not sure how that would even work

13:01 dnolen: tomoj: perhaps talking past each other. I don't see why you can't have clojure.test in the CLJS repo as a macro include.

13:02 tomoj: won't it conflict with the existing clojure.test?

13:03 dnolen: tomoj: ah right. ok, then I guess it has to be cljs.test which has the macros. and people will need to resolve the ns differences w/ feature expressions

13:05 tomoj: I wonder how we can do jvm-side fixtures

13:05 or if that requires something more like one.test

13:07 I also wonder how to compile with *load-tests* false..

13:09 dnolen: tomoj: I think getting the minimal useful set is a good start :)

13:21 dakrone: jkkramer: hey, when will clojuresphere be updated?

13:21 jkkramer: last updated was in October

13:23 jkkramer: dakrone: I'll run the script today. I keep running into issues getting a proper dump of projects from github and end up disablng the auto-update

13:23 dakrone: jkkramer: ahh okay

13:24 jkkramer: the project needs some love and I haven't had time

13:46 augustl: how do you typically manage the creation of the base schema when using datomic? I'm thinking some kind of leiningen task would do.

13:52 crease: technomancy: slept on it. think you're right about multimethods

13:56 aaelony: I have a map that may contain a variable number of (differing) keys, :k1, :k2, ..., :kn. Depending on the keys present, various functions specific to that particular key need to be called to process the values of that key. There may be a lot of keys to look for. Considering a macro or a function that tests if the map contains a paricular key and then finds the function to be called. Or possibily the Maybe monad? Curious to hear

13:56 people's thoughts on how best approach. https://www.refheap.com/paste/7755

13:58 S11001001: aaelony: write a variadic version of update-in that takes pairs of keypaths and functions and ignores absent keypaths

13:59 aaelony: S11001001: nice idea, thanks. I wonder if I should make a collection of the keywords (and names of the functions for each) and then pass that around.

14:00 hyPiRion: aaelony: when :k1 exists, should you assoc :k1-post or :k1 with the value computed?

14:00 aaelony: for debugging purposes, I'm keeping the both for now. Ultimately, only the post will matter.

14:00 hyPiRion: okay

14:01 I'll see what I can come up with on the fly.

14:01 aaelony: wow, cool thanks.

14:03 hyPiRion: I've been working with merge functions for some time now, so it's kinda relevant to what I'm currently working on :p

14:03 aaelony: i think it may be a kind of (cringing…) design pattern.

14:04 was looking at http://clojuredocs.org/clojure_contrib/clojure.contrib.monads/maybe-m but not sure if it is a fit, or performant, clean, etc...

14:06 hyPiRion: aaelony: https://www.refheap.com/paste/7756

14:06 aaelony: hyPiRion: that looks really nice

14:07 hyPiRion: I don't know how the functions you have look like though, but it should be pretty fast too

14:07 If there are many, you should probably pop a transient!, assoc! and persistent! in there.

14:07 aaelony: some functions call java libraries, others call regexes, or compute stuff...

14:08 very cool

14:10 i like the use of reduce-kv

14:10 hyPiRion: aaelony: If there are many keys - like, I think more than 16 hits per map, then this should be faster: https://www.refheap.com/paste/7757

14:11 Though it is slower if you have many functions

14:11 aaelony: there are something like between 10 and 50 keys

14:11 hyPiRion: few*

14:11 Then the first one should do just fine

14:11 I think...

14:11 aaelony: super to know both, will test

14:12 hyPiRion: Oh yeah, I haven't actually tested them, so I may have some typo in there. But the idea is idea, so it shouldn't be hard to fix it.

14:12 /s/is idea/is there/

14:13 aaelony: understood

14:13 TimMc: hyPiRion is making up for the swearjure session yesterday. :-P

14:13 aaelony: for the more intense functions I might throw a future or something in there too

14:13 ivaraasen: TimMc: swearjure?

14:13 aaelony: big thanks

14:14 hyPiRion: aaelony: Ah, sounds smart. You should do two passes then - one where you future everything, and another where you deref everything.

14:14 And good luck

14:14 aaelony: thanks - sounds good

14:14 hyPiRion: ivaraasen: swearjure is clojure without alphanumerics

14:15 like, uh

14:15 ,(`[#'~(`[~@'`[~@[]]](+))](+)) ; But I don't want to go there today

14:15 clojurebot: (var clojure.core/apply)

14:15 TimMc: ivaraasen: https://gist.github.com/3916042

14:15 ivaraasen: and https://gist.github.com/3036120

14:16 ivaraasen: beautiful

14:16 TimMc: This is what will make everyone want to use Clojure.

14:17 hyPiRion: "Screw brainfuck and javascript, Clojure is the new obscuria"

14:17 TimMc: I think the first function we should get is juxt, by the way

14:18 TimMc: hyPiRion: JS is way better at this: http://utf-8.jp/public/jjencode.html

14:18 hyPiRion: It'd be easy to do conditionals then

14:18 TimMc: Ugh, except that site has encodign issues.

14:18 hyPiRion: TimMc: Currently yeah, but Clojure has potential

14:19 and it runs on the jvm!

14:20 * hyPiRion walks slowly away...

14:26 gtrak: TimMc: that's amazing

14:26 llasram: (inc TimMc)

14:26 lazybot: ⇒ 27

14:29 squidz: if I have a function (myfun [p1 p2 p3] ...) how can I use a sequence (v1 v2 v3) for the parameters of myfun?

14:29 amalloy: &(doc apply)

14:29 lazybot: ⇒ ------------------------- clojure.core/apply ([f args] [f x args] [f x y args] [f x y z args] [f a b c d & args]) Applies fn f to the argument list formed by prepending intervening arguments to args. nil

14:30 squidz: amalloy: ah thanks, so that's what apply is for

14:37 Anderkent: Can anyone recommend a graph library for clojure 1.4?

14:38 ohpauleez: Anderkent: What sort of graph problem/features are you looking for? Like a Graph DB, or just nice graph DSs?

14:39 brehaut: or graph rendering?

14:39 Anderkent: transitive clojure, grouping, topological sort

14:39 basic stuff

14:41 hiredman: ~ping

14:41 clojurebot: PONG!

14:43 ohpauleez: Anderkent: I usually use a mix of the standard data structures, with functions to treat them like graphs, and zippers.

14:43 But you might also look at this: https://github.com/jkk/loom

14:44 There was an old contrib you could resurrect as well.

14:44 Anderkent: right, that's more or less what I found, though I hoped that there would be something already stable for something as basic as what I need. Thanks

14:44 ohpauleez: Or find a solid Java library, and just use it via interop (wrapping things into functions where it helps composition)

14:45 brainproxy: Anderkent: if you're at all interested in a graph database, OrientDB is pure java and pretty nice, and there is a clojure wrapper, clj-orient

14:45 ohpauleez: Anderkent: No problem - for most of my graph problems, I just end up using the basic clj ds's

14:46 especially with clojure.walk and zippers

14:46 brainproxy: the apis for the db support various graph operations, as you might expect

14:46 eh, looks like clj-orient is lagging behind orientdb by a couple of point releases

14:58 bbloom: dnolen: saw you starred namin / TAPL-in-miniKanren-cKanren-core.logic, and saw in the readme: " It turns out that implementing general set operations in a pure logic system, when the domain is not already known, is an extremely difficult open problem."

14:58 dnolen: bbloom: that's mostly about the difficulty of unifying sets, which isn't interesting to me at all.

14:59 bbloom: dnolen: are there any decent articles, papers, things to look at regarding infinite domain constraint problems? i'm curious how that would even work

14:59 dnolen: bbloom: now that we have a constraint system, I think we can bring most Clojure operations as constraints

14:59 SegFaultAX: dnolen: What's the best online resource to learn about unification?

15:00 dnolen: we do (assocc x k v) the way we do (+fd x y z)

15:00 we can do

15:00 bbloom: dnolen: yeah, that's clearly the next step for core.logic and i'm excited to see it unfold

15:01 amalloy: SegFaultAX: http://starwars.wikia.com/wiki/Unification_War

15:01 SegFaultAX: amalloy: Hah :)

15:01 bbloom: dnolen: I was just curious to understand "stubornly see for myself their limitations in expressing type systems."

15:02 dnolen: SegFaultAX: chapter 3 of William Byrd's thesis is a good introduction to the idea via miniKanren's implementation

15:02 tbaldridge: amalloy: illogical in this context that article is

15:02 SegFaultAX: dnolen: You wouldn't happen to have a link handy, would you?

15:02 bbloom: SegFaultAX: http://gradworks.umi.com/3380156.pdf

15:02 i've been meaning to read it myself

15:02 SegFaultAX: bbloom: Danke.

15:03 dnolen: bbloom: well Kiselyov & Byrd have show you can do some interesting things - HM type inference / checking / inhabitation very succinctly

15:03 bbloom: nominal logic programming is also very interesting - Prolog style programming to do inferences about names, binding and scope

15:04 bbloom: and I have a hunch that with CLP(Set) you could probably get through most of Types & Programming Languages

15:04 bbloom: dnolen: k, got Cheney & Urban's paper about that open

15:05 mehwork: is there a more clojuric/idiomatic way of doing System/exit

15:06 ivaraasen: dnolen: know of any any semi-technical (applied) primers on logic programming?

15:06 amalloy: usually the answer is to type out (System/exit 0) then hit backspace 19 times and do something more flexible

15:06 bbloom: mehwork: if you're using agents, remember to call (shutdown-agents) other than that exit 0 is fine

15:06 SegFaultAX: ,(count "(System/exit 0)")

15:06 clojurebot: 15

15:07 amalloy: oh, i made a mistake with wc

15:08 dnolen: ivaraasen: I always recommend starting w/ a good Prolog text, Sterling & Shapiro Art of Prolog or Bratko's Prolog for AI book

15:08 mehwork: 15?

15:09 ivaraasen: dnolen: will look into it. thanks

15:09 mehwork: the number of chars of the string, ah

15:09 SegFaultAX: amalloy: Even 25 would have been fine :) ##(count (str `(System/exit 0)))

15:09 lazybot: ⇒ 25

15:09 mehwork: what's ##

15:10 dnolen: ivaraasen: there's an early draft PDF of Concepts Techniques & Models of Computer Programming on CiteSeer, also a good read especially to understand the constraint aspect of core.logic

15:10 bbloom: mehwork: inline evaluation for lazybot ##(inc 5)

15:10 lazybot: ⇒ 6

15:10 mehwork: is lazybot on github

15:11 amalloy: $whatis source

15:11 lazybot: source is http://github.com/flatland/lazybot

15:12 ivaraasen: dnolen: I believe that book is part of my coursework next year actually

15:13 dnolen: ivaraasen: that's cool! :)

15:13 ivaraasen: we have a course on programming paradigms using Mozart/Oz

15:14 looking forward to it

15:14 hyPiRion: ivaraasen: I have the book if you need. I'm not in Trondheim now though

15:15 And I suppose it's going to be next year, not the upcoming semester.

15:15 mehwork: whenever i read through others' clojure code i never see any if statements. Are they frowned upon beause there's usually a better alternative in clojure?

15:15 ivaraasen: correct

15:17 mehwork: basically i want to know what the best way to write: run this function if this var is equal to 5

15:17 hyPiRion: mehwork: no else?

15:18 mehwork: nope, nothing approaching a switch/case

15:18 SegFaultAX: mehwork: With a lack of an else branch, when is usually good.

15:18 mehwork: nor ternary

15:18 hyPiRion: (when (= 5 var) (funcall))

15:18 mehwork: ah thanks

15:19 can you when / else or do you have to if/else

15:19 hyPiRion: mehwork: if

15:19 dnolen: bbloom: Nada Amin is at EPFL doing PL things like this http://www.cs.uwm.edu/~boyland/fool2012/papers/fool2012_submission_3.pdf

15:20 hyPiRion: ,(when (= 1 1) (prn 1) (prn 2)) ; <-- mehwork

15:20 clojurebot: 1

15:20 2

15:20 SegFaultAX: mehwork: And before you ask, if you have more than 1 branch/alternate, cond is usually good.

15:20 mehwork: ,(if (= 1 1) (prn "hmm"))

15:20 clojurebot: "hmm"

15:20 hyPiRion: ^ or case, if that's working

15:20 mehwork: shouldn't i just do that then since it reads better

15:21 even if there's no else

15:21 bbloom: dnolen: interesting. i'd be excited to see logic programming subsume typed programming

15:21 hyPiRion: mehwork: Noone's stopping you :p

15:21 mehwork: 'when' feels like it's something that'd be related to a loop or event of some kind

15:21 hyPiRion: If you feel it reads better, then do it that way.

15:21 mehwork: hyPiRion: i know :p just wondering what the convention is

15:21 dnolen: bbloom: she's porting Byrd's nominal logic stuff to core.logic which pretty exciting. It's forcing a generalization of the constraint stuff I have in place and in pretty interesting. I don't know of many constraint solvers that focus on reasoning about programs - so perhaps we going down a interesting path not tread by other constraint solvers.

15:22 SegFaultAX: mehwork: It's arguably more idiomatic to use `when` if there is no alternate.

15:22 hyPiRion: mehwork: There's no "when"-over-"if" rule, if that's what you're asking

15:22 dnolen: bbloom: heh, I don't see that happening. But certainly I think having logic programming available makes it easier to understand model what type systems can do.

15:22 hyPiRion: But it explicitly tells the reader that there's no else-part here

15:22 mehwork: ok

15:22 amalloy: hyPiRion: well, more like there's two conflicting when/if rules

15:23 ivaraasen: I mostly use "when" when the else clause would just return nil

15:23 bbloom: dnolen: i could see type systems being expressed in terms of extensible logic programs

15:23 dnolen: i'm nto saying types go away, i'm saying that logic programming becomes the underlying mechanism by which types are more useful and less restrictive

15:23 hyPiRion: amalloy: conflicting?

15:23 wat

15:24 teach me, amalloy.

15:24 SegFaultAX: mehwork: One word of caution (and this is mostly personal choice), don't use else with if-not. Negating a negation can be quite confusing.

15:24 amalloy: hyPiRion: most people's style is to use 'when wherever possible, such that 'if implies there's two clauses; if you see an 'if with only one clause from such a programmer, it indicates a mistake

15:24 dnolen: bbloom: perhaps, tho typed logic programming is a thing - see Mercury.

15:25 amalloy: a non-trivial minority use 'when only if there are side effects; thus the presence of a 'when helps notice the trickier spots with mutation

15:26 SegFaultAX: amalloy: That usage of when hadn't occured to me, but thinking back I've definitely seen code that used a convention similar to what you just described.

15:26 bbloom: dnolen: will look at it

15:27 amalloy: SegFaultAX: technomancy is the most vocal about preferring that style, if you want to ask him about it

15:27 hyPiRion: Well, I'm in some middle spot then. I excplicitly expand (if test res) to (if test res nil) and use when pretty seldom. Probably when I need mutation.

15:27 ivaraasen: dnolen: seen this paper? not sure if all of it would translate to core.logic, but it's a pretty neat example of applied Prolog. http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.52.5750

15:27 bbloom: dnolen: my interest in all this stuff is purely intellectual entertainment at the point in time

15:28 brehaut: amalloy: now i want 'when!

15:28 clojurebot: amalloy: therfor I return [previous] if rest is empty

15:28 SegFaultAX: brehaut: What would the bang signify?

15:28 amalloy: really, clojurebot? really? what do i have to unlearn you to avoid these echos from my past?

15:29 clojurebot: forget amalloy: therfor I return [previous] if rest |is| empty

15:29 clojurebot: I forgot that amalloy: therfor I return [previous] if rest is empty

15:29 brehaut: SegFaultAX: that its for doing side effecting operations that are unsafe within a transaction, just like it always does

15:29 it would probably be worth making 'when! wrap 'when in 'io!

15:30 dnolen: ivaraasen: WOW that looks awesome. Yes using core.logic to generate Clojure programs is definitely a goal, not sure how easy it would be translate that. Someone should try :)

15:30 bbloom: it is very intellectually entertaining :) tho it's been exciting to see people put this logic stuff into production.

15:31 SegFaultAX: dnolen: I watched a talk about miniKanren where they procedurally generated all the scheme programs that evaluated to 6. That was pretty neat.

15:31 dnolen: SegFaultAX: yeah that's a great talk, the relational interpreters are neat.

15:31 ivaraasen: SegFaultAX: that sounds awesome. any recordings of the talk?

15:31 SegFaultAX: ivaraasen: Yes, let me find it.

15:32 dnolen: SegFaultAX: it's pretty easy to port that stuff to core.logic now Nada Amin has already done the quine generator.

15:32 brehaut: (defmacro when! [test & body] (list 'io! (list* when test body)))

15:32 SegFaultAX: ivaraasen: http://blip.tv/clojure/dan-friedman-and-william-byrd-minikanren-5936333

15:33 ivaraasen: SegFaultAX: thanks

15:34 SegFaultAX: brehaut: I didn't even know io! was a thing til just now. Thanks for that.

15:34 ivaraasen: No problem! :)

15:35 dnolen: I hadn't heard about that! Source?

15:35 TimMc: brehaut: Alternatively, (defmacro when! [test & body] `(when ~test (io! nil ~@body)))

15:35 lucky: hi

15:36 dnolen: SegFaultAX: http://github.com/namin/TAPL-in-miniKanren-cKanren-core.logic/blob/master/clojure-tapl/tapl/src/tapl/quines.clj

15:36 brehaut: SegFaultAX: incidentally, compare 'swap! (for atoms) to 'send (for actors) for the semantic differences of bang names: send is safe in transactions because its held till the transaction succeeds, whereas atoms always swap

15:36 TimMc: (move the io! inside)

15:36 brehaut: TimMc: i wondered about that too. im not sure about more precise warning vs consistently warning

15:36 TimMc: Also note the nil.

15:37 SegFaultAX: brehaut: Could you clairfy held till the transaction succeeds? Does that mean that it won't actually send until it's comitted by the STM?

15:37 TimMc: io! takes an optional first string arg...

15:37 brehaut: SegFaultAX: yes

15:37 TimMc: oh really. huh

15:37 amalloy: TimMc: `(io (do ~@body)) seems more legible to me

15:39 SegFaultAX: amalloy: But that also prevents you from using a custom error message, no?

15:39 amalloy: so does his putting the nil in

15:39 SegFaultAX: Oh, true.

15:40 amalloy: Is there any cost to having a redundant do block?

15:40 amalloy: no

15:41 ivan: IDEA costs less than Sublime Text today

15:41 amalloy: and it wouldn't matter if there were, because i'll bet you a dollar (io! nil a b c) expands to (io! nil (do a b c)) anyway

15:41 SegFaultAX: dnolen: I don't think I'm quite far enough long in my core.logic understanding to absorb this yet. But it is quite short and elegant _looking_.

15:42 amalloy: That's why I asked if it incurred any cost since yours would expand to (io! nil (do (do a b c)))

15:42 dnolen: SegFaultAX: heh yeah, it'll make sense in good time

15:42 amalloy: well, i suppose that's true, it probably does. doesn't cost anything though; it's just as expensive as a {} in a C language

15:45 i prefix all my macros with `(do (do (do (do ~@whatever)))) because i want the user's code to sound like it's humming

15:45 TimMc: :-D

15:46 brehaut: (do (do (do (do (repeat "yeah")))) ← nirvana song

15:46 zerokarmaleft: `(do (do (do (do (do (do (do (do ,@menamena))))))))

15:46 wink: lol

15:46 TimMc: damn you

15:46 dnolen: ,'(foo ~x ~@y)

15:46 clojurebot: (foo (clojure.core/unquote x) (clojure.core/unquote-splicing y))

15:46 zerokarmaleft: oops, semi-schemified that

15:46 * dnolen finally understands why that might be useful ...

15:48 amalloy: zerokarmaleft: good thing you didn't totally schemify it. it doesn't work nearly as well with (begin (begin (begin ...)))

15:53 ivaraasen: SegFaultAX: my jaw dropped when I saw the generated code. so cool

15:54 bbloom: but did they ever get 120 to produce 5! ? :-)

15:55 SegFaultAX: ivaraasen: Tell me about it :)

15:59 hyPiRion: ivaraasen: yeah, it's pretty awesome.

15:59 dnolen: bbloom: I believe one of their students might have

15:59 bbloom: dnolen: bad ass.

16:00 how long before rich can write down a slide deck and generate datomic? :-)

16:00 dnolen: bbloom: haha, it really only works for very simple languages - things bog down when you add too many features

16:00 bbloom: dnolen: of course, extreme combinatorial explosion

16:01 hyPiRion: dnolen: Are you telling us Clojure is not simple!?!?

16:01 ;)

16:01 dnolen: hyPiRion: :)

16:02 hyPiRion: Mr. Hickey has been lying to us the whole time, then.

16:02 dnolen: hyPiRion: heh "toy" or "model" language may be a better choice of words.

16:02 hyPiRion: dnolen: I know what you meant :p

16:02 bbloom: dnolen: in an entertainingly abstract philosophical sense, all programming is a search problem: you're looking in the infinite sequence of 0s and 1s for the program that does what you want. but that would take infinite time, so you need to employ some novel ideas to reducing that search space. i could imagine if you started encoding those ideas into your distribution strategy, you could solve more and more difficult logic problems

16:03 egghead: ~search and constraint~

16:03 clojurebot: I forgot that ~paste is forget ~paste

16:03 TimMc: ~botsmack

16:03 clojurebot: clojurebot evades successfully!

16:03 dnolen: bbloom: yeah, Will used some called condp where you could weight different language forms to eliminate unlikely programs

16:03 at the Conj

16:03 bbloom: dnolen: yeah, something like that

16:04 dnolen: would be interesting to also describe things like structural recursion, such that logic programs could try to solve "what's the base case? what's the reductive step?" to generate a recursive algorithm

16:04 dnolen: expressing those novel ideas is challenging, for sure

16:05 TimMc: Novel ideas? They were probably codified in the 70s. :-P

16:05 bbloom: TimMc: i mean novel in the sense that they are worth remembering

16:09 ivaraasen: bbloom: my dream would be to have a parser do amortized analysis of an algorithm, rewrite it and generate a complementary data structure as well, i. e. a monoid for a finger tree. but that would probably be insanely difficult to do correctly

16:09 hyPiRion: Oh, the sufficiently smart compiler.

16:10 Raynes: weavejester: Are you going to put out a new version of codox?

16:11 mehwork: in a .clj file how do you go about a global/reusable var?

16:14 TimMc: mehwork: What do you mean by a global var?

16:15 ivaraasen: hyPiRion: do you know any NTNU faculty members that are enthusiastic about FP/logic?

16:15 mehwork: ah def alone does it within the namespae it seems. Does order matter? eg do you have to declare the var at the top before you can use it

16:15 TimMc: mehwork: Vars are declare-before-use, yes.

16:15 mehwork: TimMc: just something i can def at the top of the file and then reuse it in diff methods in defn's

16:16 TimMc: Sure, you could (def foo (atom 5)) and then later refer to foo.

16:16 mehwork: when you declare a ns at the top of a file clojure automatically applies it to just that entire file

16:18 TimMc: why an atom instead of just (def foo 5)?

16:19 TimMc: mehwork: Just an example.

16:20 mehwork: think i need a good book on clojure. piecing it together over google and irc is kinda hard

16:21 S11001001: mehwork: check the clojure mailing lists; several book discussions have occurred

16:27 hyPiRion: ivaraasen: About logic, I'm not 100% sure. We had Tore Amble, but he died (:'( ) in January this year. Keith Downing is the only FP-guy I know of

16:28 We're an endangered species up here, it seems.

16:28 ivaraasen: too bad

16:28 PVV had a Clojure course though, right?

16:29 mehwork: do lispers believe in reincarnation or just recursion

16:30 ivaraasen: mehwork: they believe in a higher order at least.

16:30 mehwork: :)

16:30 and parallel dimensions

16:31 hopefully in at least one of them i'm not a noob right now

16:31 gtrak: do you guys ever feel like you want a null-object?

16:31 hyPiRion: ivaraasen: No, NVG had. I remember since I held it :p

16:32 gtrak: or some kind of way to specify and propagate contracts up a function stack? (checked exceptions.. shudder)

16:34 hyPiRion: gtrak: null-object?

16:34 gtrak: recursive docstrings...

16:34 hyPiRion: I'm pretty happy with nil.

16:34 ,(class nil)

16:34 clojurebot: nil

16:34 gtrak: hyPiRion: yea, it's not the nil that bothers me so much, it's the (if ..)

16:35 we use it for convenience, if-let, but it's not always obvious what it signifies

16:36 about 3 functions deep and it gets confusing... something needs to return a value

16:37 m0smith: rhc app start -a jbossas-7

16:37 Application jbossas-7 does not exist

16:37 gtrak: nullity-overloading is obfuscating... I guess is what I mean.

16:40 hyPiRion: whut

16:41 An element is truthy if it's not nil or false.

16:41 (Except (Boolean. false))

16:42 gtrak: hyPiRion: I mean for example... say you have a database... (store/delete ... returns the entity or nil if it doesn't exist)... somewhere up the stack you can rely on this and use an if-let

16:42 if there's too many steps in between the behavior and the branching... it's confusing

16:43 I don't want to make all my functions polymorphic, because that's called java :-)...

16:44 mattmoss: something like -?>

16:44 gtrak: I wonder if there's a better way to think about it

16:44 hyPiRion: So it's the nil-punning you don't like?

16:44 gtrak: yea

16:45 and the fact that it's so darn convenient :-)

16:45 hyPiRion: It's a design decision with pros and cons

16:46 gtrak: ah, yea, I'm not criticizing the feature, but rather looking for an alternative

16:47 hyPiRion: oh, right. check out the -?> as mattmoss mentioned

16:47 it will short-circuit when nil is given as a result in the pipeline

16:48 gtrak: right :-).. I suppose that makes nil-punning more evident

16:48 hyPiRion: You could also return a keyword instead if that makes sense

16:48 :not-found for your database-example

16:49 Though that depends on whether the object can be :not-found, of course.

16:49 gtrak: right, or exceptions.. it's an interesting lib-design problem

16:49 weavejester: Raynes: Codox 0.6.4 released

16:49 Raynes: weavejester: You're a good guy.

16:49 weavejester: Hope you feel better. :)

16:50 arrdem: ,(inc weavejester)

16:50 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: weavejester in this context, compiling:(NO_SOURCE_PATH:0)>

16:50 arrdem: (inc weavejester)

16:50 lazybot: ⇒ 6

16:50 arrdem: hur dur been a while

16:50 clojure-newb: cemerick: Hi, just trying to connect to your mock friend app with basic auth via curl…. but I'm getting stuck… getting a 404 atm, should be possible shouldn't it ?

16:50 weavejester: Raynes: I made the mistake of going to work a little too soon, so I felt absolutely terrible on Wednesday, but a little better now :)

16:53 janusmcintyre: Is there a more idiomatic way to do something like https://www.refheap.com/paste/7763 ?

16:54 I want to resolve the namespace + function from a string at runtime.

16:57 hyPiRion: ,(-> "clojure.pprint/cl-format" read-string resolve meta :ns)

16:57 clojurebot: #<Namespace clojure.pprint>

16:57 hyPiRion: ,(-> "clojure.core/read" read-string resolve meta :ns)

16:57 clojurebot: #<Namespace clojure.core>

16:58 hyPiRion: Don't know if that's better though

16:58 janusmcintyre: hyPiRion nice

16:58 ,(-> "clojure.core/read" read-string resolve meta :ns)

16:58 clojurebot: #<Namespace clojure.core>

16:58 janusmcintyre: ,(-> "foo.bar/read" read-string resolve meta :ns)

16:58 clojurebot: nil

16:59 hyPiRion: It'll resolve names available in the current namespace, so I'm not sure if it's good.

16:59 ,(-> "clojure.set/union" read-string resolve meta :ns)

16:59 clojurebot: nil

16:59 hyPiRion: ,(require '[clojure.set :as set])

16:59 clojurebot: nil

16:59 hyPiRion: ,(-> "clojure.set/union" read-string resolve meta :ns)

16:59 clojurebot: #<Namespace clojure.set>

17:02 janusmcintyre: hyPiRion it doesn't resolve namespaces that are not in the current namespace

17:03 hyPiRion: yeah, I figured as much

17:04 melipone: hiya!

17:04 how do I get all the values of an assoc list? I knew how to do that and I forgot

17:04 cemerick: clojure-newb: definitely; but, instead of looking at mock_app.clj (which I only wrote for testing, really), go check out https://friend-demo.herokuapp.com/

17:05 justin`: melipone: vals

17:05 cemerick: the sample apps there are very minimal, and should be easy to copy, paste, and run with

17:05 melipone: justin`: thnaks

17:05 cemerick: FWIW, I'm not spreading that URL around yet; I want to have ~10 example apps ready, and it needs to not look like trash.

17:06 clojure-newb: ^^

17:06 janusmcintyre: hyPiRion I guess that code is not that bad then.

17:08 hyPiRion: janusmcintyre: I've not fiddled too much with ns and resolving vars in code, so I'm not the guy you should ask ;)

17:09 It's not looking bad though, if that's what you're asking.

17:10 janusmcintyre: hyPiRion Thanks anyways. I searched around Github for something similar, but found nothing. If this is too hackish, I guess I'll find out soon enough

17:10 clojure-newb: cemerick: thanks… must have missed that

17:10 yedi: is there like a protocol or spec or format or something that can be used for storing/sending boolean rules (combinations of logical statements)

17:10 cemerick: didn't miss anything; I've not linked it anywhere yet

17:14 clojure-newb: cemerick: thanks for the pointer

17:24 melipone: quit

17:40 Thad_: "Victim's rights group" ,<-- want to see if this str contains the values "rights" OR "group"

17:42 callen: Thad_: http://clojure.org/other_functions#Other%20Useful%20Functions%20and%20Macros-Regex%20Support ?

17:42 Thad_: just do an (or ...) of two presence-checking regexes?

17:43 pendlepa1ts: or use the regex #"(rights|group)"

17:44 callen: pendlepants: I was trying to make it composable and able to treat as a list or something rather than a single block of regex.

17:44 pendlepants: so that if it needs to be dynamically changed at runtime it doesn't lead to some kind of stygian horror.

17:49 hyPiRion: ,(some #(.contains "victim's rights group" %) ["rights" "group"])

17:49 clojurebot: true

17:50 hyPiRion: ,(some #(.contains "not in this one!" %) ["rights" "group"])

17:50 clojurebot: nil

17:52 Thad_: hyPiRion: perfect.. just use Java's .contain .. right ??

17:52 lazybot: Thad_: What are you, crazy? Of course not!

17:52 hyPiRion: Thad_: yes, it's not harder :)

17:53 hey lazybot, you're talkactive today eh

17:53 $findfn [1 2] 2

17:54 lazybot: [clojure.core/second clojure.core/last clojure.core/count clojure.core/peek clojure.core/fnext clojure.core/rand-nth]

17:56 borkdude: funny that rand-nth comes up

17:57 $findfn [1 2] 2

17:57 lazybot: [clojure.core/second clojure.core/last clojure.core/count clojure.core/peek clojure.core/fnext clojure.core/rand-nth]

17:57 borkdude: $findfn [1 2] 2

17:57 lazybot: [clojure.core/second clojure.core/last clojure.core/count clojure.core/peek clojure.core/fnext clojure.core/rand-nth]

17:57 borkdude: (rand-nth [1 2])

17:57 ,(rand-nth [1 2])

17:57 clojurebot: 2

17:57 callen: ,(rand-nth [1 2])

17:57 clojurebot: 1

17:58 borkdude: I would expect findfn sometimes not to list it, other times it would

17:58 aperiodic: $findfn [1 2 3 4 5 6 7 8 9] 9

17:58 lazybot: [clojure.core/last clojure.core/count clojure.core/peek]

17:58 borkdude: $findfn [1 2] 2

17:58 lazybot: [clojure.core/second clojure.core/last clojure.core/count clojure.core/peek clojure.core/fnext]

17:59 borkdude: ah there it is('nt) ;)

17:59 justin`: jackpot

18:01 Thad_: hyPiRion: This channel has a REPL ???

18:01 lazybot: Thad_: Yes, 100% for sure.

18:01 Thad_: cool

18:03 aperiodic: ~botsnack

18:03 clojurebot: botsnack is scoobysnack

18:04 aperiodic: clojurebot: forget botsnack |is| scoobysnack

18:04 clojurebot: I forgot that botsnack is scoobysnack

18:04 aperiodic: ~botsnack

18:04 clojurebot: Thanks, but I prefer chocolate

18:05 aperiodic: seems odd that inferences trump commands

18:06 technomancy: odd is what clojurebot does best

18:06 amalloy: aperiodic: botsnack isn't a command either

18:06 callen: $botsnack

18:06 lazybot: callen: Thanks! Om nom nom!!

18:08 borkdude: $inventory

18:08 amalloy: it's just a thing someone taught him a fixed reply to, a while ago

18:08 hyPiRion: $findfn [1 2] 2 2 2

18:08 callen: amalloy: don't demystify it.

18:08 lazybot: [clojure.core/if-not clojure.core/dosync clojure.core/sync clojure.core/condp clojure.core/nth clojure.core/get clojure.core/and clojure.core/locking clojure.core/io! clojure.core/when]

18:09 aperiodic: amalloy: oh, i see. that's less odd, then

18:09 hyPiRion: curious thing, this guy. I asked for fns, but got more or less just macros.

18:10 callen: $findfn [0 1] 1

18:11 lazybot: [clojure.core/second clojure.core/last clojure.core/peek clojure.core/fnext]

18:11 callen: k, so I'm not insane.

18:11 well I am, but not about that.

18:11 amalloy: fnext. if there's any function we don't need in clojure.core, that's gotta be it

18:12 borkdude: ,(doc fnext)

18:12 clojurebot: "([x]); Same as (first (next x))"

18:12 callen: LOL

18:13 amalloy: at least it's not (caadddddr ...)

18:13 amalloy: I actually figured it was people like you that enjoyed having fnext in core.

18:13 amalloy: so you could golf harder on 4clojure.

18:13 amalloy: fnext instead of second? no thanks

18:14 callen: saves one character though!

18:14 amalloy: callen: have you looked at https://groups.google.com/group/clojure/msg/0dfda3a9360cbc4b ? it's a cute cadar-thing

18:14 hyPiRion: I could swear that was the docstring for second

18:15 ,(doc second)

18:15 clojurebot: "([x]); Same as (first (next x))"

18:15 hyPiRion: Oh, I see.

18:15 amalloy: somewhere i have a version with fewer bugs, but the broken version is just as entertaining

18:15 Thad_: Should I get an array / list when returned for this: (re-find #"rights|group" "Victims' rights group") ???

18:15 lazybot: Thad_: How could that be wrong?

18:15 callen: amalloy: that tickles my black little ex-CL'er using soul.

18:16 [cadr "1.0.2-SNAPSHOT"] <--- totally worth the bytes added to the jar.

18:17 amalloy: that implementation makes me so sad

18:18 callen: amalloy: did you use CL?

18:18 amalloy: for about a month

18:18 callen: because I have to say, that pretty well numbed me off to "bad libraries"

18:18 oh, it was my first real language

18:18 after GW-BASIC and C.

18:18 I just kinda assumed after CL that most communities had god-awful libraries like that.

18:18 then I learned C# and Python. That was a bit of a shock.

18:26 are async/await in C# analogous to futures and promises in Clojure?

18:28 I guess they aren't.

18:28 solves a similar problem though.

18:29 brehaut: callen: promise / future concepts are analagous to the primatives await/async in .net are built on i believe

18:29 callan: the API differs though

18:30 callen: i imagine that with (protocol) monads you could produce something very similar though

18:32 callen: brehaut: well await is really just "dereference this promise and wait please.", right?

18:32 or future, I guess.

18:32 not promise. Sigh, sorry for bad clarity.

18:32 brehaut: I decided to go with Hiccup btw, for templating.

18:32 so *raspberries*

18:33 main reason is that frontend guy wants to learn clojurescript anyway. Thinks hiccup would be a good way to force him to sink-or-swim with Clojure. Wouldn't normally be viable and definitely couldn't get away with it at the day job.

18:33 brehaut: callen: right. i think thats pretty much it. implementing and return bind on futures (or promises) lets you have nice syntax though

18:34 callen: brehaut: to be fair, with C#, if you don't make it very obvious, the community won't know how to use it.

18:34 brehaut: I think that's partly why they made F#, to differentiate the community a bit and give them a good test bed for features for C#.

18:35 brehaut: callen: for reference, F# implements a comptuation expression over its primative values to do just that (computation expression ~= monads/do notation)

18:43 callen: brehaut: I've always like F#'s balance of strict/lazy semantics

18:43 it's a pity the Haskell people used their language as a test-bed for lazy semantics.

18:50 mehwork: is there a way using lein to make it so m clojure app is self executable, e.g., my if my project's name is 'foo' to be able to just invoke it with ./foo rather than java foo.jar

18:51 AimHere: That introduces platform dependencies straight off, and loses you one of the reasons you're using the JVM in the first place, I'd have thought

18:54 technomancy: mehwork: there's a lein-bin plugin that sorta does that; not sure if it's been maintained

18:54 gtrak: mehwork: there's existing solutions to turn jars into executables, by bundling a jvm

18:55 mehwork: ok so it's bsaically acceptible to distrubute my app and have my users type 'java bla.jar'?

18:55 znDuff: mehwork, java -jar bla.jar is the usual thing, yes.

18:55 mehwork, ...many operating systems will also let users directly run jars as executables, btw

18:55 mehwork, ...including Linux, using the binfmt_misc kernel extension.

19:06 Bergle_1: ooh nice personal licenses 75% off jetbrains (intellij + others) http://www.jetbrains.com/specials/index.jsp

19:07 mehwork: end of the world sale lol

19:08 (thanks technomancy gtrak znDuff)

19:08 hyPiRion: I've heard GNU is doing the same. They reduced their prices on emacs by 100% today

19:08 gtrak: 100% less freedom?

19:08 where do I sign up?

19:08 mehwork: i heard they were doing the opposite: for the end of the world they were making proprietary code

19:10 free as in north korea

19:10 znDuff: Is the JetBrains site actually usable now?

19:10 I tried buying an upgrade earlier today, and it was completely swamped.

19:11 ivaraasen: who needs JetBrains when you have ed?

19:11 ivan: you can buy but you don't get a license immediately

19:11 mehwork: idk, the idea of a sale on software feels like an abusive spouse who promises to only hit you once because it's valentines day. Still not excited

19:12 * znDuff prefers/uses Emacs for Clojure, but IDEA is darned handy when unfortunate enough to be writing Java.

19:12 mehwork: i've been using vim without any clojure plugins. It's been painfulish

19:12 znDuff: ...yes, that would.

19:13 mehwork: but i'm just learning the basis of the lang still, not working on a large project

19:13 znDuff: I can't do Clojure without paredit.

19:13 ivaraasen: IDEA does look very nice

19:14 n_b: IDEA is great for Java, could not make me dump vim for anything else

19:14 hyPiRion: So it's worth buying even though you're not programming Java frequently?

19:14 gtrak: the problem with me buying IDEA is it assumes I will have to use enough java some day to need it :-(

19:14 it's depressing

19:14 Bergle_1: i can drive emacs a bit, im good with vim, but i am spending more time in emacs for paredit :) even though i dont like emacs much - maybe ill get use to it

19:15 ive done a fair bit of javascript and webstorm or any of the ide's is great for javascript with refactoring.

19:19 n_b: Bergle_1: tried paredit.vim?

19:21 Bergle_1: no havnt.

19:22 Raynes: Bergle_1: I use Emacs with evil-mode.

19:22 I enjoy it very much

19:23 Bergle_1: im plodding away with emacs-live, which i realise is lots more than just paredit, but some bits seem amazing

19:23 Raynes: Note that I was an Emacs user that tried Vim and then went back to Emacs and started using evil-mode. I don't use it because I have an attachment to vim keybindings, I use it because I like modal editing and thing it is a good fit in Emacs.

19:23 ivan: non-modal editing makes me corrupt something in my .org files every few hours

19:27 hyPiRion: Uh, is there any specific reason why numerator and denominator throws exception when given integers?

19:28 It's okay that they call a method on a Ratio, but couldn't one make a protocol on top of it instead?

19:29 bbloom: hyPiRion: seems reasonable for those methods to be polymorphic. it might just be a case of evolution, an accident of history

19:29 seangrove: Is there a way to list keys for watchers given a ref?

19:30 bbloom: hyPiRion: did you search the mailing list? you may want to start a thread and or submit a patch

19:30 seangrove: ref/atom/whatever was passed into (add-watch ...)

19:30 hyPiRion: bbloom: No, I'll do that later on

19:30 amalloy: the code in Numbers.java can't use protocols

19:30 bbloom: seangrove: not that i know of

19:30 mehwork: there's no clojure convention for global variables?

19:31 bbloom: hyPiRion: that's the accident of history that amalloy is referring to: clojurescript is able to use protocols throughout, but jvm clojure can't for many things

19:31 mehwork: like all caps or an underscore prefix, etc?

19:31 bbloom: mehwork: nope, because there are no global variables, all top level vars are always namespaced

19:31 seangrove: earmuffs?

19:31 bbloom: seangrove: earmuffs are for dynamic variables

19:31 hyPiRion: bbloom amalloy alright, thanks for input

19:32 ,(doseq [p '[bbloom amalloy]] (prn (list 'inc p)))

19:32 clojurebot: (inc bbloom)

19:32 lazybot: ⇒ 3

19:32 clojurebot: (inc amalloy)

19:32 lazybot: ⇒ 36

19:33 amalloy: seangrove: ##(.getWatches (atom nil))

19:33 lazybot: ⇒ {}

19:33 bbloom: ah amalloy didn't know that was there

19:33 amalloy: nor did i

19:34 mehwork: bbloom: i'm having a hard time knowing when to create a top-level var and a local one that i pass around

19:34 seangrove: Is ## a lazybot prefix?

19:34 hyPiRion: seangrove: yup

19:34 mehwork: seangrove: yeah

19:35 seangrove: Ok, phew

19:35 mehwork: as is ,

19:35 hyPiRion: mehwork: that's clojurebot, slight differences.

19:35 bbloom: mehwork: use a local whenever the value is only relevant in one spot

19:35 hyPiRion: But basically, yeah

19:35 seangrove: hrm, maybe .getWatches isn't in cljs?

19:35 bbloom: mehwork: use a top level whenever you want to use something throughout a namespace or between namespaces

19:35 seangrove: in cljs you can just #(.-watches %) probably, but it's an implementation detail

19:36 seangrove: Ok, I'll take a look at it then, thanks

19:36 mehwork: bbloom: well my problem is diff than that. It's more to do with 'config' variables. I guess they should go at the top so they're easier to spot

19:36 bbloom: mehwork: ah yeah, so config variables are labeled ^:dynamic and often (but not always) annotated with "earmuffs"

19:37 (def ^:dynamic *config* {:foo "default"})

19:37 mehwork: :o

19:37 bbloom: then you can use (binding [*config* {:foo "omg"}] ...) to temporarily override those values

19:37 mehwork: good to know thanks

19:37 bbloom: (doc binding)

19:37 clojurebot: "([bindings & body]); binding => var-symbol init-expr Creates new bindings for the (already-existing) vars, with the supplied initial values, executes the exprs in an implicit do, then re-establishes the bindings that existed before. The new bindings are made in parallel (unlike let); all init-exprs are evaluated before the vars are bound to their new values."

19:37 bbloom: but generally, top levels are good for config, functions, constants, etc

19:42 julienddd: Hi all, new to Clojure here. I've played with TryClojure and it's been great. What's the next thing to get started ?

19:42 I'm mostly interested in web app development, but I need more practice with the syntax, etc before jumping in

19:42 SegFaultAX: julienddd: Perhaps a book? I suggest Joy of Clojure or Clojure Programming.

19:43 julienddd: anything free and online ?

19:43 mehwork: bbloom: well when would i want to use that config binding over a normal top level for a config value?

19:44 dhm: julienddd: i think clojure programming is a better book when you're starting out

19:44 hyPiRion: julienddd: Is the syntax, the concepts or both new to you?

19:44 brehaut: julienddd: if you know about functions and maps you are about ready to start mucking about with web stuff (ring)

19:44 bbloom: mehwork: so each var has what's known as a "root binding" which is the top level default value

19:44 julienddd: brehaut: Both, I'm a java/c guy

19:44 dhm: julienddd: yeah i recommend ring too. the examples are pretty small and self-contained

19:45 bbloom: mehwork: you can override it on a per-thread basis using binding, so you'd want that if you're going to have multiple clients of your API that need their own config. for example *current-user* or something like that

19:45 mehwork: ok

19:45 SegFaultAX: julienddd: Then I doubly suggest picking up a book. There are loads of new concepts that you'll be learning along the way and it would be good to have a guided tour.

19:46 hyPiRion: julienddd: For syntax and learning about functions, the webpage http://www.4clojure.com/ is great

19:46 bbloom: mehwork: you can also use a top level var like a mutable storage, but it's better to stick an atom into that var, and then mutate the atom... this way you can pass around a pointer to the atom and use it's compare & swap semantics

19:46 vars are primarily only mutable for interactive development

19:46 cemerick: dhm: You can find a ToC and such for the O'Reilly book @ http://clojurebook.com

19:47 julienddd: Thanks everyone

19:47 SegFaultAX: julienddd: See cemerick's note.

19:47 hyPiRion: julienddd: But as other say, I'd recommend finding some book. If not, then http://java.ociweb.com/mark/clojure/article.html may or may not be of help

19:47 dhm: julienddd: yeah, see chapter 9 of cemerick's book. they have a bunch of java interop stuff there that might be fun to play with as a java person

19:47 cemerick: thanks

19:48 hyPiRion: I've seen it pop up time to time, but I haven't read it myself.

19:53 nightfly_: Practical Clojure was a good introduction for me after I had a few months experience with Common Lisp

19:54 seangrove: For those familiar with the google closure/cljs compiler output, I'm trying to track down the source of an implementation of a protocol in the chrome web console

19:55 When a function/closure is lifted out of another function and turned into a delegate, where can I find the source for that function?

19:56 mrowe: sorry if this is a faq, but I've had no luck finding anything... I am getting ClassCastExceptions in clojure.lang.Reflector/invokeInstanceMethod when passing an int (e.g. 1) to a method that expects an Integer. I kind of hoped autoboxing would happen somewhere... do I have to do it manually?

19:56 seangrove: For example, any function that takes variable arguments will call __some_other_function at the end, but I'm not sure where __some_other_function is stored

19:57 amalloy: mrowe: boxing is not the problem; somethine else is but we can't tell from your description

19:57 mrowe: amalloy: ok. what more info do you need?

19:58 amalloy: well, some actual code. so far i have "i pass an integer to a method expecting an integer, but it doesn't work"

19:58 bbloom: seangrove: a good trick is to stick a # in front of a form and paste it into the rhino repl

19:58 seangrove: that echos a pretty printed bit of java code

19:58 mrowe: amalloy: :) what is the preferred pastebin again?

19:58 hyPiRion: refheap

19:58 amalloy: anything is fine. refheap or gist

19:58 znDuff will complain if you use pastebin

19:59 mrowe: https://www.refheap.com/paste/7768

20:00 if I call it with an object that has a method setMaxCount(Integer count) and a params map { :max-count 1 } it fails, but { :max-count (Integer. 1) } works

20:00 amalloy: &(class 1)

20:00 lazybot: ⇒ java.lang.Long

20:00 bbloom: Raynes will complain if you don't use refheap

20:00 mrowe: amalloy: ah

20:01 amalloy: it would work if the method took int rather than Integer, i think

20:01 mrowe: yeah

20:01 amalloy: the compiler does that downcast for you

20:01 mrowe: I think that's why it's worked for me before, but is tripping up now

20:01 amalloy: cheers

20:09 seangrove: bbloom: Do you primarily use the rhino for your cljs repl env?

20:09 bbloom: seangrove: no, rhino is slow as hell. it's just convenient to run ./script/repljs to get a rhino repl

20:09 seangrove: Heh, thought so

20:12 technomancy: oh dear

20:12 oh dear oh dear

20:12 " hasattr(object, name) The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not. (This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not.)"

20:12 seangrove: Damn, it seems like Shoreleave just stopped adding atom watchers...

20:12 technomancy: http://docs.python.org/2/library/functions.html#hasattr

20:12 brehaut: technomancy: im sorry to hear

20:12 callen: technomancy: what's wrong?

20:12 technomancy: callen: the last sentence?

20:13 callen: technomancy: Python?

20:13 technomancy: brehaut: makes clojure.core/contains? look positively well-adjusted

20:13 callen: yeah

20:13 callen: technomancy: Python is my day job, so I can sympathize.

20:13 brehaut: technomancy: amazingly thats the most sane way to do it due ti the amount of 'magic happens' in object member lookups

20:13 callen: technomancy: Python is resents what I subject it to. Like 6 call-deep pipes of map/lambda/filter/reduce

20:13 Python resents*

20:14 brehaut: technomancy: absolutely

20:14 callen: brehaut: oddly, if getattr(obj, "field", False): hasn't burnt me yet.

20:14 brehaut: callen: because it does all that magic for you.

20:14 callen: brehaut: most Pythonistas have enough taste not to abuse method_missing-esque DSLs like Ruby.

20:14 I had an epiphany earlier today about Ruby and Python, actually.

20:15 I realized Python had more function-oriented than class-oriented APIs than Ruby because Ruby doesn't have real namespacing.

20:15 for some reason, this hadn't occurred to me before.

20:15 bbloom: Python seems to not worry about using exceptions for control flow

20:15 it's part of the iterator protocol!

20:15 tpope: callen this recently dawned on me as well

20:15 bbloom: StopIterationExcepetion

20:15 brehaut: bbloom: death to iter

20:15 callen: bbloom: slingshot?

20:15 tpope: it makes me happy to know this wasn't 100% obvious to everyone else.

20:16 tpope: it seriously explains a lot though.

20:16 TimMc: bbloom: Maybe that's where prototype.js picked that up from.

20:16 tpope: I guess I've never seriously worked in a language with real namespaces before

20:16 callen: I *hate* class-based APIs.

20:16 they always end up abusing some stupid stateful series of instantiated class-scope data to make it work.

20:16 bbloom: tpope: it's actually a big deal. i've been considering writing a blog post about the importance of actual namespaces

20:16 callen: bbloom: you should tell the C people about it, see what they think. :P

20:16 bbloom: i was considering an inflamatory hacker news bait title like: "The Node.js REPL is Broken"

20:16 :-P

20:17 tpope: it's growing on me

20:17 callen: bbloom: I knew namespaces were a big deal, what I hadn't done was connect that to why Python users use more functions and Ruby people use more classes for exposing functionality.

20:17 bbloom: callen: yeah, it makes sense

20:17 callen: FQNS 4life.

20:17 seangrove: callen: Maybe

20:17 bbloom: callen: but even python suffers from a dynamism fail with namespaces

20:18 technomancy: callen: modules work great in Ruby for namespacing, but for some reason people prefer classes. I don't understand it at all.

20:18 callen: bbloom: erm, yeah, I'm guilty of a few things there.

20:18 seangrove: Mix-ins are kind of an interesting patch to get class-based things to look more like function-based things

20:18 bbloom: if you do `from foo import bar` and then re-def bar in foo, the previously imported name is not modified

20:18 callen: technomancy: you can't be trusted, you work for sie enemy.

20:18 bbloom: hence you see advice to `import foo.bar as bar`

20:18 callen: seangrove: the mix-ins vs. MI thing is a total canard.

20:18 seangrove: MI?

20:18 clojurebot: Nakatomi space is http://bldgblog.blogspot.com/2010/01/nakatomi-space.html

20:18 callen: seangrove: most Python multiple-inheritance gets used like Ruby mixins.

20:18 there's very little difference.

20:18 tpope: yeah you can't do the selective import thing in ruby

20:19 callen: beyond the fact that Python gives you a little more power.

20:19 seangrove: Ah, I wasn't thinking of inheritance

20:19 bbloom: there's also a few decent traits based libraries for python

20:19 tpope: and there's no real replacement for refer

20:19 bbloom: which are slightly less shitty than mixins and multiple inheritence

20:19 callen: most Ruby code I've seen is require "blah" -> BOOM GOES THE REFERENCES

20:19 (enjoy yer monkeypatchin')

20:19 bbloom: def Module.const_missing

20:19 *cringe*

20:19 callen: I've never seen anything approaching sensible namespacing in Ruby.

20:20 tpope: imagine if you had to call Clojure::String.join each time

20:20 callen: bbloom: ick.

20:20 another thing I noticed about classes/objects is that the composability and dimensionality is annoying

20:20 bbloom: UserPreferences -> const_missing -> user_preferences -> 'models/user_preferences.rb' -> require -> "oh that was cool" -> THE HORROR

20:20 callen: when you use very method-centric APIs you're basically forced to treat every single piece of code like a special snowflake

20:21 instead of as being a generic sequence, IFn, etc.

20:21 bbloom: callen: or abuse send :-)

20:21 callen: I originally came to Clojure thinking it would fix everything I didn't like in CL. Realistically, it fixed what I didn't like about Python and Ruby.

20:21 bbloom: i've been guilty of writing modules with functions like frob_foo and frob_bar and then doing send("frob_#{thing.class.name.underscore}")

20:22 it's sorta like multimethods :-P

20:22 callen: bbloom: that is *unholy*

20:22 seangrove: Dynamic!

20:22 bbloom: when you don't want to make a class for every enum in your database, it's quite reasonable heh

20:23 callen: bbloom: no I understand it, I've had to do some evil stuff in Python as well. I just resent being forced to do so.

20:23 bbloom: agreed

20:23 callen: bbloom: most Python meta-programming for me involves getattr, setattr.

20:23 because it works against classes, modules, etc.

20:23 so I can dynamically snag database models by stringly name, etc.

20:23 getattr(models, "User

20:23 ", None)

20:23 then I'll usually wrap up the None/Option/MaybeMonad stuff with a bind wrapper

20:23 because I hate if-checking None.

20:23 brehaut: class Foo(call_to_class_generater("blah")):…

20:24 my least favorite python dynamism trick ever

20:24 callen: brehaut: I try to avoid piercing the veil between runtime and compile-time in Python and Ruby.

20:24 Python tends to bite you very hard if you do things that trip-over into compile-time.

20:24 good example of this: default args

20:24 obviously if you understand the semantics it's not a big deal, but it's really not a great idea.

20:25 it'll confuse most people who haven't run into it before.

20:25 it's like a "run once" macro.

20:31 lewis1711: I just try to avoid python fullstop

20:32 callen: lewis1711: you could do a lot worse.

20:32 lewis1711: I bet I could name 20 programming languages that are worse.

20:33 technomancy: lewis1711: if you know of another SSH implementation that wouldn't require writing a C extension to OpenSSH lemme know =)

20:33 lewis1711: Cobol, Brainfuck, raw machine code... :)

20:33 technomancy: fair play. it does have nice libraries

20:34 technomancy: oh man there are pastebin links flying fast in this channel

20:34 * technomancy covers znDuff's eyes

20:35 callen: lewis1711: Erlang, most C libraries (yes, they're their own languages. Don't believe me? Look at ffmpeg. F!@#ing crazy frog.), Ruby, Common Lisp, C++, JavaScript, Go, Pascal, Java, Scala, Vala, C#, Haskell, Perl, PHP, Smalltalk, OCaml, APL

20:35 oh and Ada.

20:35 technomancy: that's cheating

20:35 also, you forgot VB

20:35 brehaut: and VBScript

20:36 seperate class of evil

20:36 technomancy: also, OCaml is awesome

20:36 tpope: cobol if you really want to dig into the junk drawer

20:36 brehaut: also haskell

20:36 lewis1711: sorry were you listing all the languages people should use instead of python?

20:36 technomancy: and smalltalk, wtf dude?

20:36 lewis1711: PHP... I dunno that doesn't belong there. I'll give you that

20:36 callen: technomancy: there is a hypothetical parallel universe where OCaml and I are like this: http://www.youtube.com/watch?v=5utC5fvY-Zs

20:36 technomancy: we are not in that universe.

20:37 technomancy: that is some wonderful CG

20:37 lewis1711: meh, suspend your disbelief :)

20:37 callen: we are in the universe where obscure academic francophones implemented OCaml and batteries included came out way later than it should've been. Also, I don't want to work for Jane Street.

20:38 technomancy: I guess it depends on whether you're talking about quality of the language or suitability for use at $DAYJOB

20:39 callen: technomancy: you've got a point there, but I try to incorporate my nighttime funsies into my day job

20:39 technomancy: privilege of working in startups I guess.

20:39 brehaut: huh 'ring.util.request/body-string

20:39 handy

20:41 seangrove: How can I use a local copy of a cljs library in lein-cljsbuild?

20:42 Nevermind, I think I'm doing it with clojurescript already, can probably figure it out via :dependencies

20:42 gfredericks: lein checkouts!

20:42 callen: so am I the only one trying to find ring.util.request right now and failing at life?

20:43 weavejester: callen: It's in Ring 1.2.0-SNAPSHOT.

20:43 callen: oh god dammit

20:43 weavejester: thank you.

20:43 weavejester: do you know which github branch that is?

20:43 weavejester: I'm going to try and release Ring 1.2.0 sometime within the next month or so

20:44 callen: master

20:44 * callen flips his table and walks away

20:44 callen: that's what I was in.

20:44 wait wait, I'm a moron. h/o

20:44 no no, false alarm.

20:44 weavejester: ring.core?

20:44 ring-core, that is.

20:44 weavejester: Right

20:45 * callen purses lips

20:45 callen: oh. wrong fork.

20:45 weavejester: https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/util/request.clj

20:45 callen: weavejester: mmcgrana has too much google juice man.

20:45 sigh, sorry.

20:46 brehaut: shit. i bet im not helping with that

20:46 callen: brehaut: how so?

20:46 brehaut: by linking to the mmcgrana repos

20:46 callen: brehaut: s'not cool man, you confuse idiots like me :(

20:47 brehaut: huh. either i have completely forgotten about fixing the links, or someone has benevolently hacked my site

20:49 turns out you can thank utvc

20:49 callen: I started listening to the Neverending Story OST because of the earlier reference. I need to do this everytime I code.

20:52 TimMc: callen: ┬─┬ノ( º _ ºノ)

20:53 brehaut: (╯°□°)╯︵ ┻━┻

20:56 callen: TimMc: I'm happy to announce that the war is over, we were never at war with Oceania.

20:56 TimMc: we've always been at war with Eurasia all along.

21:30 TimMc: &(let [& [1 2 3] [& &] & [& &] & [& &] &] &)

21:30 lazybot: ⇒ (1 2 3)

21:44 gfredericks: &(let [& [1 2 3]] &)

21:44 lazybot: ⇒ [1 2 3]

21:46 Guest77224: #lighttable

21:57 TimMc: gfredericks: Well, that too.

21:58 Did you see the Swearjure session yesterday evening?

22:03 gfredericks: wat?

22:03 clojurebot: For Jswat: start clojure with -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8888

22:03 TimMc: gfredericks: Y'know, Curje.

22:03 gfredericks: currj?

22:03 TimMc: Clojre without alphanumerics.

22:04 and the letter \u, apparently...

22:04 gfredericks: oooh

22:04 man I thought you were talking about a meetup or something

22:04 like some hip city whose clojure group is called swearjure

22:04 TimMc: Mmm, swearjure meetup...

22:04 gfredericks: no I was at a meetup yesterday evening actually

22:05 TimMc: gfredericks: There *is* a meetup with a name reminiscent of that, I think.

22:05 gfredericks: seajure?

22:05 clojurebot: seajure is the seattle clojure group: http://seajure.github.com

22:05 TimMc: Hah, no.

22:05 gfredericks: clojurebot: swearjure?

22:05 clojurebot: No entiendo

22:06 gfredericks: data science on the obama campaign

22:09 TimMc: Oh hey, when did the clojure.org docs link move to Github and get versioned? (... v1.3, v1.4, v1.5)

22:10 ,(doc reset-meta!) ;; what's this useful for?

22:10 clojurebot: "([iref metadata-map]); Atomically resets the metadata for a namespace/var/ref/agent/atom"

22:12 TimMc: ,(when-first [x (range)] x)

22:12 clojurebot: 0

22:15 TimMc: Hmm, how is drop any different from nthrest?

22:16 amalloy: TimMc: nthrest eagerly consumes the first n elements

22:17 TimMc: Mmm, right.

22:20 gfredericks: while drop waits till you call first on it? so it's like rest/next?

22:21 (defn drop [n coll] (lazy-seq (nth-rest n coll)))?

22:21 amalloy: yeah, i think that's correct

22:21 TimMc: It looks like drop doesn't allow GC on the head until the first call to first or seq.

22:28 brehaut: i think i must be completely ignorant on how to use java.io classes

22:28 but how do you create a stream that can be read from and written to‽

22:28 amalloy: brehaut: start from the assumption that they're rubbish

22:28 brehaut: wonderful :/

22:28 amalloy: well, there's no such thing

22:28 brehaut: amalloy: that seems to be the case

22:28 amalloy: but it sounds like you might be happy with a Piped[Input|Output]Stream pair

22:29 depending on what you want that stream for. file writing, or what?

22:29 TimMc: Concurrent communication?

22:29 * gfredericks needs a two-way stream for what

22:29 brehaut: amalloy: interstitial stream for catting multiple other stream things to

22:30 eg, i have a bunch of files from clojure.java.io/resource and i want to make one stream that reads from them in order so i can feed it to std in of a conch program

22:31 so far i can only assume ive grabbed the whole problem complete bass ackwards

22:31 amalloy: $google SequenceInputStream javadoc

22:31 lazybot: [SequenceInputStream (Java 2 Platform SE v1.4.2)] http://docs.oracle.com/javase/1.4.2/docs/api/java/io/SequenceInputStream.html

22:31 brehaut: phew

22:31 thanks

22:31 amalloy: yes, copying to a "buffer" is pretty backwards

22:31 you want to construct a stream which delegates. in this case, that is already written for you (though with a terrible API)

22:32 you'll also want ##(doc sequence-enumeration), i think it's called

22:32 lazybot: ⇒ nil

22:32 amalloy: &(doc seq-enumeration)?

22:32 lazybot: ⇒ nil

22:32 brehaut: enumeration-seq

22:32 amalloy: no, that's the wrong direction

22:32 brehaut: oh

22:33 amalloy: brehaut: you could also just steal from me: https://github.com/flatland/io/blob/develop/src/flatland/io/core.clj#L30

22:33 brehaut: ah that will do

22:33 thanks

22:33 amalloy: i wonder what the "opts" arg is for

22:34 brehaut: consistency with clojure.java.io/… ?

22:35 jkkramer: forward-compatibility with a version yet to be written

22:39 amalloy: ah yes, consistency with c.j.io/make-input-stream

22:39 i think in theory you can write (c.j.io/input-stream [stream1 stream2])

22:40 and it calls (make-input-stream [stream1 stream2] nil), so we register an implementation of that

22:41 brehaut: clojure.java.io is one of those libs that if you arent writing clojure regularly is quite confounding

22:42 * gfredericks is still confounded by it

22:42 brehaut: likewise

22:42 gfredericks: you just try things and it always works for the 4th thing you try

22:42 brehaut: it doesnt help that the java library is obtuse at best

22:42 gfredericks: then you forget the details of what made it work and repeat that 2 months later

22:42 amalloy: it's certainly not as transparent as (most of) clojure.core

22:43 gfredericks: ,(doc monitor-enter)

22:43 clojurebot: Gabh mo leithscéal?

22:43 amalloy: thinking about it now i'm quite impressed by how readable clojure.core is, on the whole

22:43 brehaut: yeah both statements are true

22:44 gfredericks: I'm surprised that the define-the-first-four-arities pattern was never generalized

22:44 or automated somehow

22:44 brehaut: my impression of c.j.io is that it looks like it does a lot of clever for me, but i just cant work out what exactly

22:44 amalloy: gfredericks: it's pretty hard to do. i think at some point rich welcomed someone to solve it

22:44 brehaut: gfredericks: i think heroic efforts were undertaken around 1.2/1.3 but it stumped allcomers

22:45 gfredericks: amalloy: yeah I had the sense that might be the case

22:45 amalloy: i spent an hour or two on it and gave up

22:45 brehaut: i think fogus might have got pretty close but not close enough

22:45 gfredericks: it's a bit like loop unrolling isn't it

22:46 amalloy: loop unrolling seems more structured to me

22:57 TimMc: What's this about arities?

22:57 gfredericks: I guess I need to find an example

22:58 alandipert: gfredericks: you mean like [] [a] [a b] [a b c & more], the stuff that's all over math?

22:59 TimMc: Oh, all those monoids!

22:59 gfredericks: alandipert: I suppose...math?

22:59 https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L600

22:59 ^ there's an example

22:59 oh no not monoids

22:59 it's specifically when there's an unnecessary number of small arities defined before the vararg case

22:59 brehaut: amalloy: am i missing something? i should be able to just require flatland.io.core and it should registers a make-input-stream implementation for seqable things (such as vectors) right?

23:00 alandipert: gfredericks: oh, i was thinking math because i've hung out there… another neighborhood in core.clj, lol. but yeah it's all over

23:00 gfredericks: I mean probably they are monoids but they're defined that way for perf, not just for being monoids

23:00 amalloy: brehaut: that's the plan, yep

23:00 brehaut: i must be doing something stupid then

23:03 technomancy: flatland.io.core? =(

23:04 brehaut: whats the opposite of turtles?

23:04 technomancy: shredder

23:05 brehaut: cause its those, all the way up

23:05 its shredders all the way up

23:05 amalloy: (dec shredder)

23:05 lazybot: ⇒ -1

23:06 TimMc: [core.core/core "1.0.0-SNAPSHOT"] (:require [core.core.core.core.core :as core])

23:06 brehaut: http://www.rottentomatoes.com/m/core/

23:07 audiences agree: core is not good

23:12 TimMc: brehaut: Oh lord, you prompted me to read the plot of that on Wikipedia... christ that's terrible.

23:13 brehaut: TimMc: its a better movie than its plot

23:13 but only just

23:13 and because its firm mocking itself

23:13 TimMc: Is it?

23:13 brehaut: only just

23:13 the plot is rubbish, the movie is slightly entertaining rubbish

23:14 i still wouldnt watch if given a choice

23:22 alandipert: it does have that sweet shuttle LA river landing scene, which is how i justify naming my namespaces core

23:24 brehaut: lol

23:41 frozenlock: woohoo! Cljs in cljs!

23:45 clj-newb-234: is (= (m-bind (m-result value) function)) (function value)) correct? or should i be (= (m-bind (m-result value) function) (m-result (functoin value))) ?

23:45 http://onclojure.com/2009/03/06/a-monad-tutorial-for-clojure-programmers-part-2/ (in referene to)

23:46 amalloy: clj-newb-234: the latter looks right to me

23:47 TimMc: frozenlock: Really?

23:49 amalloy: clj-newb-234: i think actually it's the former. let's take the specific case of the List monad: f is then a function from x->[x]. so (m-result 5) is [5], and (m-bind [5] f) calls (f 5), which is expected to return a list

23:49 frozenlock: TimMc: taken from HN https://github.com/kanaka/clojurescript

23:49 clj-newb-234: amalloy: looking at http://www.haskell.org/haskellwiki/Monad_Laws , it appears to be the former

23:51 TimMc: frozenlock: Hmm, what makes this *not* self-hosted?

23:53 frozenlock: ?

23:54 clj-newb-234: can "(m-bind (m-result value) function)" be wrritten in domonad notation? I don't believe it's equiv to: "(domonad [x (m-result value)] (function value))"

23:56 TimMc: frozenlock: Well, it claims to not be a self-hosted compiler, but it also claims to be a (mostly working) CLJS compiler that can compile itself.

23:57 Hmm, or is it that the standard Clojurescript compiler can compile it, but it has some parts it can't compile for itself yet?

23:58 frozenlock: That would make sense

Logging service provided by n01se.net