#clojure log - Jun 24 2011

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

0:06 gko: I don't use leiningen/cake, only REPL+files+ad hoc scripts: are they like ASDF/quicklisp of CL?

0:08 cemerick: gko: lein and cake both provide dependency management via the maven model; so yes, they're similar to quicklisp in that respect.

0:09 symbole: cemerick: Pretty much. It would be nice to be able to extend the editor based on interfaces, and not on assigning values to seemblingly random global variables.

0:09 cemerick: I agree.

0:09 Tough road to tread, tho not because of the language.

0:10 gko: cemerick: lein vs cake: which one is better?

0:10 * cemerick isn't touching that one with a 50 foot pole :-D

0:11 gko: got it :)

0:12 are they both matures?

0:12 cemerick: gko: FWIW, AFAICT, lein drives the "standard" for project.clj files, and it's been around longer, and its more widely used. Cake provides some nifty bits that lein doesn't though.

0:13 Both are used for real projects in real companies, if that is a reasonable barometer.

0:13 gko: do they download JARs for each project or they put them in a common pool?

0:14 cemerick: Both of them reuse maven's ~/.m2 repository structure IIRC.

0:14 There was some talk of cake switching to use ivy, but I don't know how that settled out.

0:14 gko: so, the latter, though each lib needs to be downloaded at least once of course.

0:15 gko: cemerick: OK... I intend to put all that stuff in my Dropbox directory...

0:15 cemerick: stuff?

0:16 gko: cemerick: all these JARs, etc...

0:16 cemerick: gko: yeah, don't do that. :-) Back up ~, but don't put any effort into curating your own store of jars.

0:17 gko: cemerick: well, If leiningen/cake does the work, for the better...

0:18 cemerick: exactly; dependency management means never touching jars directly

0:47 technomancy: gko: to be honest, it seems to me like most people who learn clojure aren't to keen on going back to CL

0:47 it can be done, but I'm not sure how. wouldn't be surprised if you had to keep them in separate Emacs instances

0:49 *too keen

0:49 the fact that the slime devs say "just use CVS" with a straight face may have something to do with it

0:51 cemerick: keeps out the riff-raff

1:02 technomancy: anybody try that vagrant script?

1:02 tomoj: clojure-box?

1:03 oh, found it

1:22 gko: technomancy: that's what I do now... Emacs 1: use CVS or ELPA version; if use other Lisp: open Emacs 2 and corresponding SLIME.

1:24 technomancy: regarding not going back to CL: quicklisp happened and it's a whole new world :)

1:24 technomancy: gko: it's impossible to make stable releases that are compatible with a constantly-changing target like slime CVS

1:24 their release management is simply irresponsible

1:24 hopefully quicklisp puts some pressure on them to go out of cowboy mode; who knows

1:25 gko: technomancy: agreed. Another solution would be to change ELPA version so that CVS and ELPA versions don't collide and can be used on the same instance.

1:26 technomancy: key bindings would still conflict

1:28 gko: technomancy: in CL REPL/buffers, use CL semantics, in Clojure REPL/buffers, use Clojure semantics?

1:30 technomancy: it's not that simple; you'd have to have two copies of every single slime function, and you'd have to also have a third function for each binding that would detect the major mode and dispatch to the right version

1:31 it would be easier to make swank-clojure work with current slime CVS, but then it would just break in another month or so, so it's hard to get the motivation

1:40 gko: technomancy: what I meant was to make the ELPA version totally separated from the CVS version, it would be called something like SCIME, so that there are no common names... SLIME (M-x slime) for CL, SCIME (M-x scime) for Clojure.

1:41 Of course, it would a permanent temporary solution...

1:41 technomancy: could work. but I'm not gonna do it. =)

1:42 gko: technomancy: of course not, you focus on clojure & contribs :)

1:42 justinlilly: technomancy: it worked for me in the updated version, fwiw.

1:42 though I had trouble getting jack-in to work with the seajure website.

1:42 some large exception that I just ignored.

1:43 technomancy: justinlilly: hm; I actually only tested jark

1:43 kind of attached to the idea of launching jark in ~/.profile though; I may add that to my host

1:44 justinlilly: do it. it already takes forever for the thing to come up from nothing.

1:44 technomancy: oh, the vagrant script already launches jark in .profile =)

1:46 it's not much different from lein install swank-clojure 1.3.1 and ~/.lein/bin/swank-clojure though I guess

1:48 feng: help

1:52 13:49 -clojurebot- recently on clojars.org: #{"org.clojars.mschristiansen/lein-beanstalk"}

7:47 tsdh: Hi

7:50 I have a function that produces a finite lazy seq + an alternative eager version. The eager version is about 6 times faster. However, if I replace calls to the lazy fn to calls to the eager version, performance doesn't increase too much, although in my tests, I nearly always realize the seqs completely.

7:52 The only explanation that I can come up is that (map foo (lazy)) possibly applies foo even before lazy is completely calculated while (map foo (eager)) first computes the seq and then reiterates it mapping to foo. Is something like that correct?

7:53 manutter: tsdh: it certainly true that (map foo (lazy)) will start mapping before lazy finishes computing -- that's what "lazy" means

7:54 tsdh: manutter: Ok, then I'm happy my guess is correct. :-)

7:55 manutter: The lazy seq should come back much quicker than the eager one for the same reason.

7:56 You said it was generating the eager seq more quickly than the lazy seq, though? Is that right?

7:56 tsdh: manutter: Yes, that's the case. (eager) is 6 times faster than (doall (lazy)).

7:56 manutter: oh, faster than lazy inside a doall

7:57 that kinda makes sense though I'm surprised the lazy would be six times slower than the eager

7:58 but if the code to generate the seq is really small/fast, I suppose the lazy-seq overhead could be relatively large by comparison.

7:59 or there could be some inefficiencies in how you're generating the lazy version.

7:59 tsdh: manutter: Yeah, the seqs are generated using fast first/next java methods in some external lib. There's no expensive calculation involved.

8:00 manutter: ok, that makes sense

8:00 You know about the built-in iterators for Java objects?

8:01 (hmm, now I'm trying to look it up real quick on clojuredocs.org and *I'm* having trouble remembering)

8:01 tsdh: manutter: Yeah, but the lazy seq thing has the charme of not being fail-fast. For example, using them I can do (map delete! (vseq mygraph)) which modifies the seq while iteration.

8:02 manutter: ah, here we go

8:02 ,(doc iterator-seq)

8:02 clojurebot: "([iter]); Returns a seq on a java.util.Iterator. Note that most collections providing iterators implement Iterable and thus support seq directly."

8:03 manutter: I believe that is lazy out of the box, if your Java object supports Iterable

8:03 haven't played with it much tho

8:03 tsdh: manutter: My lazy seqs support some additional features over the java counterparts.

8:03 manutter: gotcha

8:04 tsdh: manutter: And what happens if the underlying iterator throws a ConcurrentModificationException?

8:04 manutter: well, ordinary exception handling (or lack thereof, if you're not using try/catch)

8:05 that would be my guess anyway--like I said, I don't have much experience with it

8:06 tsdh: manutter: No, what I wanted to say is that iterators throw while my lazy seqs allow for modification on iteration. I don't want to lose that feature.

8:07 manutter: yeah, gotcha

8:07 that is, "gotcha" as in "I see what you're saying" not as in "I see a problem" :)

8:08 irc is nice but it doesn't carry tone of voice too well...

8:08 tsdh: manutter: Ok, now I think you see what I'm saying. :-)

8:08 manutter: I do, and I see the advantages of your approach

8:10 tsdh: Ok, I'm digging a bit more in the code to see where I can boost performance...

8:31 clgv: I just wondered about 'type vs 'class: the difference according to doc is that type will return the value of metadata attribute :type if present and otherwise the class. when or by what is :type metadata set?

8:40 hmmm :type is apparently not used in clojure.core 1.2

8:43 oh 1.3-beta1 was released :)

9:28 gfrlog: (defn identity [x] (type (with-meta {} {:type x})))

9:29 clgv: gfrlog: not the straight forward use case for it that I would have thought of ;)

9:30 * gfrlog wishes there were a "stupidest implementation of (identity) contest"

9:30 clgv: but since it is not used in core, I assume it's build for application specific use.

10:00 Scriptor: int

10:04 timvisher: hey all

10:04 who wants to help explain this behavior? https://gist.github.com/1044816

10:04 I have a map with a key pointing to a long

10:04 when I print that at the repl, everything's fine

10:05 if i do anything at all with it, the number turns to 0

10:05 including (first ...) or (into #{} ...)

10:05 and i haven't the foggiest why

10:08 pjstadig: not enough information to debug

10:08 what to from-long and to-long do

10:09 where is fs/mtime coming from?

10:09 timvisher: or (pr ...) for that matter

10:09 pjstadig: what is happening during the snip? is the filesystem changing?

10:09 timvisher: fs/mtime is from the fs library

10:10 $google clojure fs

10:10 sexpbot: First out of 2760 results is: ClojureWise: fs - File system utilities for Clojure

10:10 http://clojurewise.blogspot.com/2011/01/fs-file-system-utilities-for-clojure.html

10:10 timvisher: time is clj-time

10:10 $google clj-time

10:10 sexpbot: First out of 61800 results is: clj-time | Clojars

10:10 http://clojars.org/clj-time

10:10 timvisher: those

10:10 the snip is me clipping another 678kb of data

10:10 this is a 'large' seq (by my thought, at least)

10:11 my point was that the first element can clearly be seen to have the long intact before i call first on it

10:11 once i call first it turns to a 0

10:11 pjstadig: http://download.oracle.com/javase/6/docs/api/java/io/File.html#lastModified()

10:11 timvisher: to-long turns a joba time DateTime into a long

10:11 and then from-long converts a long to a DateTime

10:12 I'm familiar with what mtime is doing under the covers

10:12 that's the whole idea. i'm basically backporting an addition I just made to my app that includes dates

10:12 I can't serialize the DateTime the way i've serialized stuff so far so i need to convert it to something read can deal with

10:13 so that i can spit it out to a file and then read it back in

10:13 but in memory i'd like it to be a DateTime

10:13 pjstadig: lastModified returns 0 if there's an i/o error or if the file does not exist

10:13 timvisher: sweet

10:13 but that doesn't explain what i'm seeing

10:14 if i don't do anything to the seq resulting from the map, it prints with the expected values

10:14 it's only when i use the map that it turns to 0

10:14 that's the point of the first line

10:14 the 2 :imported-ats

10:14 pjstadig: well you're doing a complex operation here

10:14 (ref (map #(assoc % :imported-at (time-coerce/from-long (fs/mtime (wallpaper->thumbnail-path %)))

10:14 and here (map #(assoc % :imported-at (time-coerce/to-long (:imported-at %))) @library))

10:15 the best thing would be to break it apart piece by piece and see that the values are what you are expecting

10:15 timvisher: i've been at the repl for an hour over this, I could gist my whole log if that would help

10:15 in general though, i've done that

10:15 i've picked it apart piece by peace

10:15 piece*

10:15 everything returns what I want it to until i do something to the map

10:15 and then the number turns to 0

10:16 could this have something to do with them being primitive longs?

10:16 pjstadig: what is preferences-home?

10:16 you're binding preferences to {:library-cache-path "/Users/tim/Desktop/library.clj"}

10:16 timvisher: it's a path-prefix string

10:16 pjstadig: do those comport with each other?

10:17 timvisher: yes

10:17 preferences is a map that i load from a file

10:17 preferences-home is another var that has the default prefix

10:17 not terribly proud of that but haven't gotten around to doing something better yet

10:18 essentially, in the main app I have a ref called library that stores a big 'ol hash-set

10:18 dpritchett`: speaking of which i have a tiny noir app and i need a place to store my mysql password

10:19 timvisher: i make edits to that and every once in a while a serialize the datastructure to disk

10:19 in a format that can be read by read-string

10:19 dpritchett`: would a .clj file with a single def containing my secrets accessed via load-file at runtime be a good starting point?

10:19 timvisher: so far, this has worked beautifully

10:19 dpritchett`: or is there a standard config file pattern

10:19 timvisher: i've been trying since yesterday though to add a imported-at key to the structure

10:19 and it's the first java object that i'm introducing, thus my need to serialize it with conversion and then read it with conversion

10:19 and that's where i discovered this behavior

10:20 dpritchett: that's what has worked for me up until now

10:20 as long as your storing your password as a string it works great

10:21 just make sure you don't add it source control! :)

10:21 pjstadig: does that make any more sense?

10:22 clgv: dpritchett`: you could add the config-file in your home in a ".yourapplication/" folder

10:22 timvisher: dpritchett: what's also nice is that if you do testing, you can use binding forms to override the default value and point at a different db

10:22 dpritchett`: clgv how would i access it though

10:23 (load-file ".myapp/dbsecrets.clj") ?

10:23 timvisher: different: no, you need a full path to it

10:23 or make sure it's relative to launch point

10:23 pjstadig: timvisher: you're using a ref and the filesystem, assuming that the functions in your pipeline are pure, either some state is changing on you, or some of those functions in your pipeline are not producing the values you think they are

10:24 timvisher: so if you store it in ~/.myapp/foo.clj then you need to get the home location and str them together

10:24 i'm a big fan of fs

10:25 clgv: dpritchett`: like timvisher said you would have to gain the full path. maybe there is some java.io that does resolution for you. would be great since "~" probably makes no sense on windows ;)

10:25 dpritchett`: so i can't just use ~ to refer to the home location, I have to figure ito ut myself?

10:25 timvisher: java doesn't understand ~

10:25 dpritchett`: my app is mostly a toy and it's intended to be run serverside on linux fwiw

10:25 cemerick: ~ is a shell thing

10:25 clojurebot: @ has nothing to do with whether sth is evaluated or not

10:25 timvisher: fs has a home function

10:26 you don't have to store it in ~

10:26 you could also just store it relative to the root of the war/jar/project folder

10:26 then you wouldn't need a full path

10:26 the point i was making was simply that you can't use ~ to refer to user home

10:26 dpritchett`: so we're talking http://clojars.org/fs ?

10:27 timvisher: dpritchett: that's what i use to interact with the filesystem

10:27 it's a nice wrapper over File as well as some other nice functions for processing trees of files

10:27 and you get to refer to files by there path, rather than as objects, which is nice

10:27 dpritchett`: i think i'll just use a relative path for now... I am not exactly concerned with a perfect solution i just want to get the password out of my code

10:28 then i'll gitignore the config file and push it out

10:28 timvisher: pjstadig: if you're saying that state must be changing outside of the run-time and thus messing with my results, that's a good point, but it still doesn't seem to explain what I'm seeing

10:28 i can run those 2 functions over and over again and they return the same results every time

10:29 if they were changing the state i'm reading, i'd expect the results to change

10:29 pjstadig: map is lazy

10:29 so the time between when you call map and when you print or first the seq...things can happen

10:29 timvisher: again, i totally agree with you, but if that was happening, you'd expect the results to be different every time, wouldn't you?

10:30 i suppose i could do-run on the map

10:30 pjstadig: maybe it's not the solution, but it's all i got

10:30 timvisher: but the repl forces lazy seqs anyway

10:30 that's cool. thanks for your help. this behavior is just baffling to me

10:30 pjstadig: if i were you i'd break apart those complex pieces of code, and try to test things in isolation

10:30 timvisher: that's what i've been doing

10:30 pjstadig: right

10:30 timvisher: everything works exactly as expected until i use the map

10:30 pjstadig: so maybe i'm not helping :) :(

10:30 timvisher: seq

10:31 you're at least providing an ear to rant to. :)

10:31 pjstadig: the fact that lastModified returns 0 on an i/o error or if the file is missing seems like a good lead to me

10:31 that would explain seeing 0 for imported-at

10:32 and the fact that lastModified is accessing the file system which can change while you're not looking also seems like a good lead

10:32 but i agree it's weird that it is reproducible

10:33 dpritchett`: so i am using clojure.contrib.sql/with-query-results to pull from mysql and i haven't yet figured out the proper way to e.g. post the results to an html template before the connection closes

10:33 i have one function that gets me the recordset and can format/print it

10:33 and i have another that responds to an http request using noir's defpage macro at the url "/posts"

10:33 haven't figured out how to compose this exactly

10:34 Does anyone know of a good example of a simple CMS app using contrib.sql ?

10:35 clgv: do I still have to use DateTime/now or is there something in clojure 1.2.1 or contrib?

10:35 I want to use the timestamp as ID

10:36 timvisher: clgv: could you be looking for clj-time?

10:36 clgv: since I dont need any real ID management but only a reference between datasets on disk

10:36 timvisher: $google clj-time

10:36 sexpbot: First out of 61800 results is: clj-time | Clojars

10:36 http://clojars.org/clj-time

10:36 pjstadig: ,(.getTime (Date.))

10:36 clojurebot: java.lang.IllegalArgumentException: Unable to resolve classname: Date

10:36 pjstadig: ,(.getTime (java.util.Date.))

10:36 clojurebot: 1308926197290

10:36 pjstadig: can work as a timestamp

10:36 and can be compared easily

10:38 clgv: yep. I just dont want to build an own function if there is one already.

10:38 pjstadig: there is one though...it's the method on the Date class

10:39 clgv: I saw it ;)

10:39 pjstadig: suit yourself :)

10:42 cemerick: or ##(System/currentTimeMillis)

10:42 sexpbot: ⟹ 1308926534365

10:42 pjstadig: ja, was just going to say that, too

10:43 * gfrlog can't wait till the Long overflows and everybody's code breaks

10:44 clgv: cemerick: precise one :)

10:44 timvisher: so if i do the same operation without binding library, i'm golden. https://gist.github.com/1044912

10:44 manutter: timvisher: Hey, I saw your questions about daylight time yesterday (it was in my scrollback) Did you ever get that figured out?

10:44 timvisher: with binding but with refs, still broken https://gist.github.com/1044918

10:45 manutter: yes and know

10:45 no*

10:45 clgv: just checked: (-> (System/currentTimeMillis) (java.util.Date.)) to be sure that it isnt relative to system start ;)

10:45 timvisher: i figured out a way to do it

10:46 what i didn't figure out is why (time-zone-for-id "US/Eastern") and (time-zone-for-offset -5) don't return the same thing

10:46 manutter: timvisher: that is odd, unless US/Eastern is auto-updating for DST

10:47 timvisher: that's what i mean

10:47 gfrlog: Us/Eastern should be an atom that gets swapped every 6 months

10:47 timvisher: any of the relevant string ids (i.e. "America/New_York") all auto update to DST

10:47 cemerick: gfrlog: The earth probably won't exist by the time the long overflows.

10:47 ,(java.util.Date. Long/MAX_VALUE)

10:47 clojurebot: #<Date Sat Aug 16 23:12:55 PST 292278994>

10:47 cemerick: Or humanity will be extinct, whatever.

10:48 gfrlog: cemerick: you mean the earth probably won't exist BECAUSE the long overflows

10:48 timvisher: they return different types

10:48 manutter: cemerick: yeah, maybe if we were better prepared for Y2G it would be the end of everything

10:49 clgv: lol earth wont exist because of suns death by then ;)

10:49 timvisher: one is a CachedDateTimeZone and the other is a FixedDateTimeZone

10:49 manutter: yeah, but the sun uses an old MS timestamp...

10:49 timvisher: but the semantics of the functions then seem strange

10:49 when i sign up for a site and they ask me for my GMT offset, i say 5 without thinking and they select US/Eastern

10:49 -5*

10:50 gfrlog: what's 5? Israel?

10:50 timvisher: whereas it seems that if I want to use for-offset i'd have to keep track of whether that person is currently in DST

10:50 to add or subtract an hour

10:50 or whatever crazy thing that country is doing this year

10:50 manutter: timvisher: I haven't worked enough with Java dates to discuss the technical details beyond a certain rather shallow depth

10:51 timvisher: it's my first real forray as well so hurray to us! :)

10:51 clgv: timvisher: turkey switched DST later this year with an absurd reason^^

10:51 manutter: I did see a link on joda.org about updating the timezones manually

10:51 apparently that's an issue for people stuck using older jvm version

10:51 *versions

10:51 timvisher: i just know that everything i've read about joda time up until now made me think that it did DST magically, which it _does_ so long as you don't get that FixedDateTimeZone back

10:51 i just don't know why you'd ever want that.

10:52 maybe if you wanted to stick it people dumb enough to live in countries with DST (like me! ;)

10:52 cemerick: clgv: The sun still has some billions of years to it yet, no? Or am I forgetting my local astrophysics timelines?

10:52 timvisher: cemerick: you're thinking of alpha centauri

10:52 you have a suprisingly wide scope of local astrophysics ;)

10:52 the sun's going in a few years

10:53 don't worry though

10:53 clgv: cemerick: oh humm that number is only 292 million - well, guess I have to check ;)

10:53 timvisher: the government'll get us all relocated

10:53 gfrlog: hairdressers and marketing folks on the first ship

10:53 timvisher: anyone else had a chance to look at this seq problem i'm having?

10:54 manutter: Just put a dollar in the bank now, at 3% interest by the year 292M you'll be able to buy a whole solar system somewhere else.

10:54 cemerick: timvisher: A billion here, a billion there :-) http://en.wikipedia.org/wiki/Sun#Life_cycle

10:54 timvisher: manutter: that's why i don't invest in stocks

10:54 Scriptor: we're just about about halfway through the sun, I believe

10:54 tsdh: Is there a problem with generating and executing gazillions of identical anonymous functions (performance and maybe garbage collection wise)?

10:54 clgv: cemerick: damn. ok we need bigger integer types! ;)

10:55 Scriptor: manutter: or dine at a fabulously expensive restaurant and watch the universe end :)

10:55 tsdh: why are they identical?

10:55 or are you generating billions of closures?

10:56 tsdh: Scriptor: Well, not identical but equivalent.

10:56 gfrlog: can the number of functions generated be expressed by a Long?

10:57 tsdh: Scriptor: Basically, I have a type-matcher function that returns a function that accepts elements of some types. That is used in some lazy seq producing fn, and in each iteration step a new type-matcher for the *same* type is produced.

10:57 stuartsierra: tsdh: Every occurrence of `fn` in your code generates one Java class. Every time that fn expression is evaluated, it generates one instance of that class.

10:58 tsdh: Scriptor, stuartsierra: Now I wondered if it would improve performance if I refactored the code so that only one type-matcher instance is produced and passed along.

10:58 gfrlog: stuartsierra: the instance holds the closure information?

10:58 timvisher: anyone know why a long at the repl would suddenly turn to 0 upon looking at it putting it somewhere else?

10:59 i.e. https://gist.github.com/1044816

10:59 /s/looking at it/

10:59 anyone know why a long at the repl would suddenly turn to 0 upon putting it somewhere else?

10:59 gfrlog: timvisher: is that the most minimal example you can get?

10:59 timvisher: hmm. was that /s supposed to work?

10:59 no

10:59 i'll work on getting it more minimal

11:00 actually, is that minimal enough?

11:00 https://gist.github.com/1044918

11:00 i removed the binding and all of that

11:00 it's still fairly complex

11:00 baha

11:00 sorry, ignore that

11:00 gfrlog: there's all this stuff with these libraries I don't know anything about...

11:00 timvisher: have too many gists going

11:00 i'll work on something new

11:00 gfrlog: usually if you try to strip out all the ancillary stuff at some step you'll figure out the real culprit

11:01 timvisher: how do i produce a primitive long on purpose?

11:01 gfrlog: do it by accident and then later claim you meant to

11:01 timvisher: lol

11:01 that's what fs/mtime is doing so i want to remove that call

11:01 manutter: timvisher: I dunno, I looked at that code and I think you should call Schrodinger and tell him you found his cat.

11:02 clgv: roflmao!

11:02 Scriptor: tsdh: presumably it would be more performant, benchmarks would be pretty interesting to see just to get an idea of how all the class generation affects clojure performance

11:02 stuartsierra: gfrlog: yes

11:03 gfrlog: stuartsierra: cool.

11:03 stuartsierra: The instance holds the values of closed-over locals.

11:03 Scriptor: also, see if maybe you could refactor it into just one function and generate a ton of closures of it instead?

11:03 timvisher: manutter: that's what i've been looking to hear all morning! :)

11:04 stuartsierra: In general, you want to avoid generating hugh numbers classes (which can happen with `eval`). Generating huge numbers of instances (closures) should not be a problem.

11:04 timvisher: so, no one knows how to produce a long on purpose?

11:04 clgv: &(Long. 5)

11:04 sexpbot: java.lang.IllegalArgumentException: No matching ctor found for class java.lang.Long

11:05 timvisher: ,(long 5)

11:05 clojurebot: 5

11:05 timvisher: that look about right?

11:05 gfrlog: ,(.longValue (long 3))

11:05 clgv: &(type (long 5))

11:05 clojurebot: 3

11:05 sexpbot: ⟹ java.lang.Long

11:05 timvisher: god i've gotten lazy

11:05 gfrlog: docs say that Long#longValue returns a primitive

11:05 timvisher: does type do autoboxing?

11:05 gfrlog: don't know what clojure will do to it though

11:05 tsdh: Scriptor: Hm, now I refactored the function that way, and the performance is only very slightly increased. With ~1 million type-matcher each producing a new instance it takes 330ms, with one instance passed along it takes 270ms. So it seems it's not worth it.

11:06 clgv: the random version: ##(if (< (rand) 0.5) (long 5) (double 5))

11:06 sexpbot: ⟹ 5

11:06 stuartsierra: Starting in 1.3, all integer literals are longs. They will be primitive if used only in a primitive context. Anywhere else they will be boxed as java.lang.Long.

11:06 Most Clojure functions, such as type, do not support primitives, so auto-boxing occurs.

11:06 cemerick: timvisher: All primitives are boxed at function boundaries, unless the function in question has primitive type decls.

11:06 Scriptor: tsdh: see if you can check memory consumption too, just in case the gc isn't able to keep up

11:07 otherwise, an 18% speedup isn't all that bad :)

11:07 timvisher: ,(doc long)

11:07 clojurebot: "([x]); Coerce to long"

11:07 timvisher: does that mean Coerce to Long?

11:07 Scriptor: ,(doc apply-macro)

11:07 clojurebot: No entiendo

11:07 timvisher: or is that really be a bonafide `long`?

11:08 gfrlog: timvisher: does your code not break if you substitute (long 5) for your function call?

11:08 tsdh: Scriptor: Memory is hard to measure. In any case, the requirements of these functions should be negligible in comparison to the data.

11:08 gfrlog: (or (long 6) if necessary)

11:09 timvisher: i'm working on making this simpler, i just want to know if I'm on the right track for replacing that call to fs

11:09 tsdh: Scriptor: Well, yes, the speedup is not that bad, but now the interface is 50% worse. Before users would call (vseq mygraph 'SomeType), now it's (vseq mygraph (type-matcher mygraph 'SomeType))...

11:11 Scriptor: ah, maybe not worth it then, though you maybe vseq could be implemented as a wrapper macro that rewrites it that way for you?

11:11 cemerick: timvisher: it returns a long, but will get boxed into a Long if you're just passing the result on to a fn that doesn't support primitives.

11:11 Or, it yields a long, I should say.

11:11 * cemerick is talking about 1.3 here

11:12 Scriptor: how fast is java's instanceof? Asking because first/rest invoke it every call

11:12 timvisher: wow. i'm an idiot

11:12 sorry everyone

11:12 tsdh: Scriptor: vseq is a protocol function that recursively calls itself in a lazy-cat.

11:12 timvisher: i wasn't binding one of the keys i needed in the function and so pjstadig was right all along!

11:13 the path i was accessing didn't exist and thus mtime was returning 0

11:13 at binding time they existed because the preferences var hadn't been overwritten yet

11:13 i hate state...

11:13 should've been associng onto preferences rather than completely resetting it

11:14 Scriptor: tsdh: ah, you're right, sorry for the confusion

11:14 timvisher: thanks so much for everyones help

11:15 gfrlog: timvisher: did you figure it out while trying to minimize the example?

11:16 timvisher: yeah

11:16 gfrlog: :)

11:16 timvisher: which was also pjstadig advice

11:16 which i'd been doing for an hour

11:16 i just never though to not use mtime and instead insert a fixed long value

11:16 gfrlog: my strategy is to just delete random characters and see what happens

11:17 timvisher: have an emacs function that does that for you? :)

11:17 pjstadig: timvisher: glad you figured it out!

11:18 tsdh: Scriptor: Hm, but I could make a vseq function that creates a type-matcher and rename the protocol methods to vseq-1. Is there something like a private protocol?

11:18 timvisher: pjstadig: me too!

11:18 as a meta question, why does the repls forced eval not exhibit the behavior that firsts eval does?

11:20 pjstadig: i'll tell you why

11:20 map is lazy

11:21 the seq escapes the binding form in one case

11:21 but not in another

11:21 timvisher: ah hah

11:21 pjstadig: stupid laziness :)

11:22 timvisher: so the seq comes out of the binding form having not been evaluated and then gets evaluated in the unbound context

11:22 brilliant

11:22 makes perfect sense

11:22 pjstadig: vars and binding are a form of state

11:24 tsdh: Hm, the docs specify (defprotocol name & opts+sigs) but don't mention what opts can be except the optional docscring...

11:26 gfrlog: ,(source defprotocol)

11:26 clojurebot: java.lang.Exception: Unable to resolve symbol: source in this context

11:26 pjstadig: ~source defprotocol

11:28 timvisher: anyone else using clojure-jack-in in emacs?

11:31 mattmitchell: is there a non-lazy concat? or, a recursive doall?

11:32 dnolen: mattmitchell: you can always make concat non-lazy by wrapping in doall.

11:34 mattmitchell: dnolen: ok that does work, however i am composing a data structure out of a hash-map and embedded laz seqs via concat. I would like to not have to worry about using doall all over my code, and instead use doall at the last minute. But it doesn't seem to eval the nested lazy seqs. Does that make sense?

11:35 dnolen: mattmitchell: you can use doall at the last minute, doall will only operate on the lazyseq it's applied to, not nested ones.

11:35 s/can/can't

11:35 sexpbot: <dnolen> mattmitchell: you can't use doall at the last minute, doall will only operate on the lazyseq it's applied to, not nested ones.

11:36 mattmitchell: dnolen: ok good to know. I've been looking at this too... seem like a good/bad idea? http://stackoverflow.com/questions/1217131/recursive-doall-in-clojure

11:37 dnolen: mattmitchell: I'm curious as to why you need to force them.

11:38 mattmitchell: dnolen: yeah i'm still trying to figure this out. I might be doing something wrong here.

11:38 dnolen: mattmitchell: what about your problem requires you to force them?

11:39 pjstadig: i've run into the problem of doing concat of concats of concats to build up a structure, and once it gets forced at the end you get a stack overflow exception

11:39 and it was fixed but just doing (doall (concat ...))

11:39 instead of waiting until the end

11:40 gfrlog: no matter how many times I encounter that issue I can never remember why it happens

11:40 dnolen: gfrlog: recursive applications of concat is almost always the culprit

11:40 pjstadig: there's also the issue of a lazy seq escaping a scope like with-open or something

11:40 gfrlog: dnolen: like (concat a (concat b (concat c (...))))?

11:40 pjstadig: but again you can doall at the appropriate levels to get around that

11:41 dnolen: gfrlog: if you have 5000 unrealized concats, you're gonna get stackoverflow when you try to pull out the first item.

11:41 gfrlog: dnolen: I guess I can't convince myself it's necessary, given the way laziness is handled elsewhere without stacking

11:41 mattmitchell: dnolen i think actually, i'm wrong. I need to dig a little bit more before I can explain what's happening here :)

11:41 gfrlog: dnolen: 5000 nested (lazy-seq)s generally would do the same thing?

11:42 dnolen: gfrlog: exactly.

11:42 gfrlog: dnolen: I wonder why everybody's so prone to do it with concat then...

11:42 could concat be rewritten to avoid that?

11:43 pjstadig: perhaps we should all make more use of into

11:43 and infact i guess into is really a "non-lazy" concat

11:43 dnolen: gfrlog: I don't see the point, since it applies to lazyseqs in general.

11:43 gfrlog: dnolen: but apparently concat is the only place it tends to pop up

11:44 dnolen: gfrlog: only because it's commonly used in recursive operations, special casing concat sounds meh.

11:45 __name__: $source into

11:45 sexpbot: into is http://is.gd/uvV1dc

11:46 gfrlog: dnolen: well if it's meh then let's not do it

11:50 pjstadig: only problem with into vs. concat is

11:50 ,(into '(:d :e) [:a :b :c])

11:50 clojurebot: (:c :b :a :d :e)

11:50 pjstadig: ,(concat '(:d :e) [:a :b :c])

11:50 clojurebot: (:d :e :a :b :c)

11:50 dnolen: ,(into (vec '(:d :e)) [:a :b :c])

11:50 clojurebot: [:d :e :a :b :c]

11:50 pjstadig: sure

11:50 but that's cheating

11:51 hehe

11:51 dnolen: :)

11:51 pjstadig: i'm just saying you have to be aware that into uses conj which is data structure specific in terms of where it stuffs new items

11:51 but concat is also ordered the way you'd "expect"

11:52 plus

11:52 ,(concat #{:a :b} #{:a :b})

11:52 clojurebot: (:a :b :a :b)

11:52 pjstadig: ,(into #{:a :b} #{:a :b})

11:52 clojurebot: #{:a :b}

11:52 pjstadig: assuming you'd want to do such a thing

11:55 Scriptor: anyone behind clojuredocs.org on here?

11:55 the sorting algorithm used in search is a bit off

11:59 gfrlog: Scriptor: I've seen it do weirder things

12:01 I forget what I was searching for, but when searching for the function "foo" by name, nothing would come up. When I searched for another function called "foo-bar", "foo" was the first result

12:01 mattmitchell: anyone know what the command is in emacs to show a list of search matches in a new buffer?

12:02 derp_: hey, what is the != symbol in clojure?

12:02 dnolen: derp_: not=

12:02 mattmitchell: it'll show each match with a little context

12:02 derp_: dnolen: thanks

12:02 dnolen: mattmitchell: are you talking about grep-find ?

12:04 mattmitchell: dnolen: no you can do C-s, then you can pull out the matches into a new buffer, and in that buffer you can see a little context around each match. If you select one of the items, you go to that place in your main buffer. Very handy, just can't remember what it's called!

12:07 dnolen: can grep-find do that?

12:07 dnolen: mattmitchell: multi-occur ?

12:07 mattmitchell: dnolen: i'll try that

12:07 dnolen: M-x multi-occur

12:07 mattmitchell: oh that sounds right

12:07 dnolen: which is really cool, I never knew about that.

12:07 http://www.emacswiki.org/emacs/SearchBuffers

12:07 mattmitchell: dnolen: yes! thank you. very helpful.

12:09 edwardg: hello, clojure noob here - trying to run clj-http tests, but `lein run -m clj-http.run-server` gives me a classpath error. is it implicit that i need to adjust the classpath, or am i missing something basic?

12:09 derp_: I wrote this function to test for primality ( http://pastebin.com/fqL37JPN ) but for some reason it's not working, and I really can't guess why

12:10 edwardg: which tests are failing?

12:10 derp_: the first if statement should return when checking against 1 or 2, but for some reason it's returning false, which doesn't make any sense to me

12:12 hiredman: derp_: you see to expect implicit return statements in non-tail positions?

12:12 seem

12:14 everything is an expression http://stackoverflow.com/questions/19132/expression-versus-statement

12:15 derp_: so how do I make it explicit?

12:17 hiredman: derp_: there are no statements

12:18 derp_: okay, but then how do I return the evaluated expression?

12:27 cemerick: derp_: use cond instead of a pile of `if`s

12:29 There's also https://github.com/jpalmucci/clj-return-from, which I can see being handy for more complex situations

12:33 derp_: okay, I tried using cond instead, here's my code now: http://pastebin.com/MHbx04dM

12:33 but for some reason I still can't get it to work

12:35 hiredman: derp_: everything is an expression

12:37 manutter: ,(doc recur)

12:37 clojurebot: Huh?

12:37 manutter: ,(doc loop)

12:37 clojurebot: "([bindings & body]); Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein. Acts as a recur target."

12:37 dnolen: derp_: move your recur inside the cond expr as a :else clause

12:39 derp_: dnolen: thanks!

12:40 dnolen: why is it :else instead of else?

12:41 * gfrlog thinks if everything is an expression then nothing is an expression

12:41 fliebel: ,(boolean :else)

12:41 clojurebot: true

12:41 gfrlog: is that why it works?

12:41 manutter: derp_: The :else isn't actually part of the cond syntax

12:41 fliebel: &(cond false 1 :blah 2)

12:41 sexpbot: ⟹ 2

12:41 gfrlog: it hadn't occurred to me that it wasn't part of it

12:42 manutter: it's just a value that is truthy enough to serve the purpose of a "non of the above" clause

12:42 gfrlog: &(cond false 1 :never 4)

12:42 sexpbot: ⟹ 4

12:42 dnolen: derp_: because it makes the cond macro simpler.

12:43 manutter: ,(code false 1 (= 1 0) 2 :none-of-the-above 3)

12:43 clojurebot: java.lang.Exception: Unable to resolve symbol: code in this context

12:43 manutter: doh, typo

12:43 (cond false 1, (= 1 0) 2, :none-of-the-above 3)

12:43 gfrlog: ah hah ha...

12:43 manutter: and he forgets the leading comma, doh again.

12:43 derp_: okay, so it's just a random keyword that's evaluated after all other statements?

12:44 gfrlog: ,(cond :else 15 (= 1 1) "twelve")

12:44 clojurebot: 15

12:44 gfrlog: only if you put it after all the other statements ;-)

12:44 manutter: Yeah, any keyword will evaluate to true, and thus satisfy cond, which looks for the first clause that returns a true value

12:44 derp_: &(cond :blah 1 true 2 false 3)

12:44 sexpbot: ⟹ 1

12:44 fliebel: gfrlog: That's a nasty trick to unsuspecting readers :)

12:45 gfrlog: ,(conf :if 1 :then 2 :else 3 :end 4)

12:45 clojurebot: java.lang.Exception: Unable to resolve symbol: conf in this context

12:45 gfrlog: bah

12:45 I'm not typing it again.

12:45 manutter: Yeah, the "magic" is that cond tries each pair until it finds one that evaluates to a true value, so if you have an always-true value, non of the other clauses will be tried.

12:47 halfprogrammer: I think even JoC talks about using any keyword in cond instead of :else thingy

13:05 choffstein: 1

13:06 gfrlog: choffstein: 2

13:06 choffstein: Has anyone successfully deployed a war file (generated from lein-ring) on tomcat? I am having some issues trying to figure out how to get the static files to serve (using ring / moustache / hiccup) and where they should be located in the war file for tomcat to serve them

13:06 gfrlog: choffstein: does the standard resources setup not work?

13:06 choffstein: yeah ... advice to IRC GUI programmers -- don't change window context when a user is typing in their password :-\

13:07 gfrlog: your password is "1"?

13:07 choffstein: there is a 1 in it.

13:07 manutter: not any more ;)

13:07 choffstein: namely ... at the end

13:07 hence the "enter" that quickly followed it.

13:07 manutter: That's amazing I have the same combination on my luggage.

13:08 gfrlog: Now I just gotta think of all the passwords that end in "1" and pick the most plausible

13:08 manutter: "we're-number-..."

13:08 gfrlog: "321"?

13:08 manutter: So, if I admit I successfully deployed a WAR file, you're going to ask me how I did it, and I don't remember :)

13:08 *:(

13:08 choffstein: lemme throw up a quick gist of my setup...

13:09 gfrlog: a quist

13:10 manutter: iirc, I ended up with a setup that would work for war files but not for lein/repl work, and one that would work with lein/repl but not war

13:10 choffstein: yeah. that is what I am finding in online resources manutter

13:10 manutter: and I could switch between the two with the right changes to my project.clj

13:10 but I'm at work now and don't have access to those files

13:11 choffstein: maybe something about changing the project environment settings?

13:12 manutter: I think I added a special plugin or something

13:12 choffstein: well ... that's an interesting idea. is it possible to get information from your leiningen project file from inside your project?

13:13 my current issue is that my environment variables which I am trying to use to distinguish between production and development environments don't seem to be read from within tomcat...

13:13 manutter: On that question I'll defer to someone who actually knows what they're talking about

13:15 choffstein: yeah. let me get that gist up right quick

13:16 derp_: I am still having a bit of trouble getting my euler #3 program to work http://pastebin.com/MHKSNz3A

13:16 I keep getting an error about not recurring from the tail-position

13:17 I'm not really sure how to get around that, so I think I must be making some fundamental mistake

13:17 sritchie: (reverse (rest (reverse lst))) can be (butlast lst), btw

13:18 manutter: derp_: the problem is in line 29 of your gist

13:18 if I'm parsing the nesting correctly anyway

13:19 tsdh: Can I have a protocol whose methods are not exposed? Something like defn-?

13:19 dnolen: tsdh: hiding fns of protocol doesn't make sense.

13:20 derp_: so it's okay to have multiple recur statements within a function?

13:20 the error was making me think I could not do that

13:21 tsdh: dnolen: why? I use protocols for fast dispatching in my own namespace but the functionality is exposed with some more convenient interface.

13:21 dnolen: derp_: you can, but you should probably stop solving your euler problem and take a moment to understand where recur has to go. make some small simple fns to test.

13:22 tsdh: this isn't Java. imagine Clojure's core datastructures with hidden protocol fns.

13:22 choffstein: Okay, here is my project file / web.xml file / and server as well as the tomcat error I am getting (which is highly undescriptive): https://gist.github.com/1045242

13:22 sdeobald: choffstein, can you use Jetty instead? We tried Tomcat for ages before finally switching. It's much... less awful.

13:23 tsdh: dnolen: Wouldn't make sense there, but here it does.

13:23 choffstein: sdeobald: Amazon's Elastic Beanstalk is on tomcat :-\

13:23 Which is what I am trying to deploy to...

13:23 sritchie: tsdh: can you just put the protocol in some other namespace, and :use it into the namespace with your convenient interfaces?

13:23 dnolen: tsdh: protocols produce fns, you could probably alter the vars if you really want to. or use definterface and don't involve fns at all.

13:23 derp_: dnolen: I don't understand, what more do I need to know about recur except that it is an stack optimizing method for recursive calls?

13:23 or is my understanding too fundamental?

13:23 rhdoenges: with clojure.string/replace, how do I access a matched group from the RE in my replacement?

13:23 dnolen: derp_: recur needs to be in the tail poisition, you need to figure out what that means.

13:24 sdeobald: choffstein, dang. Too bad. I remember having the same static resource issue on Tomcat. Let me see if I can find an old setup.

13:24 gfrlog: ,(doc clojure.string/replace)

13:24 clojurebot: I don't understand.

13:24 tsdh: sritchie: That's an idea...

13:24 gfrlog: rhdoenges: I believe you can pass a function that takes the match vector

13:24 rhdoenges: gfrlog: ohkay. so I would pass something like (fn [[group-one group-two]] ...)

13:25 gfrlog: rhdoenges: yeah. Test it out, it's probably the case that the 0th item in the vector is not one of the groups

13:25 choffstein: sdeobald: do you know a good jetty host?

13:25 tsdh: dnolen: What's definterface?

13:25 dnolen: tsdh: for defining a Java interface.

13:26 tsdh: dnolen: But I guess then I cannot use extend-protocol, right?

13:26 sdeobald: choffstein: Nope, sorry. We're just running it ourselves.

13:27 choffstein: okay, thanks anyway :)

13:27 sdeobald: And I guess the old tomcat setup is dead. So I'm just not any help at all. :)

13:28 choffstein: my biggest issue is getting static files to serve. ring's wrap-file seems to want the directory to exist, but to create a war, the directory needs to be in "resources." I just end up having a double copy of assets to make it work :-\

13:28 rhdoenges: gfrlog: that's what was tripping me up, the first item is the whole matched part. thanks!

13:28 gfrlog: choffstein: I thought there was a handler that in the resources directory

13:28 rhdoenges: yessir

13:29 choffstein: gfrlog: eh? don't quite follow that

13:29 gfrlog: choffstein: okay lemme see what I have...

13:29 sritchie: derp_: your parens are off, on your cond statement

13:30 derp_: you close off that cond block on line 27

13:30 gfrlog: choffstein: I think it's a compojure thing. Are you using compojure?

13:30 dnolen: tsdh: yeah you can't. I guess I don't personally see much benefit in the convention ^:private when a) it can be circumvented, b) naked use is discouraged.

13:30 choffstein: nope. ring / moustache

13:30 gfrlog: choffstein: okay nevermind. I have (route/resourses "/") in my compojure routes and it finds everything in /resources/public

13:31 choffstein: well ... might be time to switch to compojure. I think moustache and compojure play nicely...

13:31 tsdh: dnolen: The obvious benefit is that you get less clutter when autocompleting. :-)

13:31 gfrlog: choffstein: I don't even know what the heck moustache is, so I can't comment on that

13:32 I thought it was this javascript templating thing but I think that's something else

13:32 sritchie: derp_: I fixed your formatting for you, and that cond error: https://gist.github.com/1045258

13:32 the code runs, now, though the answer's not correct

13:32 derp_: sritchie: thank you very much!

13:32 dnolen: tsdh: heh, what are you using? I guess it doesn't process the ns declaration?

13:33 sritchie: I didn't change any functionality, but I tweaked your implementation of prime? to show you a different way of writing statements like that

13:33 tsdh: dnolen: I use slime/swank

13:33 sritchie: derp_: or goes through each of its forms and, if it hits one that's true, returns it, otherwise it moves on. If it gets to to end, it returns the value of the final form

13:34 derp_: also, here's a nice style guide that should help you with formatting a bit: http://mumble.net/~campbell/scheme/style.txt. the key thing here is, don't treat the parens like curly braces and close them off on new lines

13:34 let the reader use the indentation as a guide... you don't really count parens, once you've read enough of this code

13:35 derp_: sritchie: thank you, I really appreciate your comments

13:35 hiredman: get paredit

13:36 derp_: hiredman: already got, although I barely know how to use it

13:36 *got it

13:36 sritchie: derp_: http://www.emacswiki.org/emacs/PareditCheatsheet

13:42 gfrlog: easiest way to make a black hole to bind *out* to?

13:43 drewr: (FileWriter. "/dev/null")?

13:43 gfrlog: drewr: okeedoke, thx

13:44 sdeobald: sritchie, that's a great sheet. derp_: you'll wind up using all of those all the time. paredit makes editing sexps a spiritual experience.

13:45 sritchie: derp_: try M-(, and go from there

13:45 do that at the beginning of some symbol, and see what happens

13:45 rhdoenges: sritchie: that is what I have been looking for. I got one of those for vim and pinned it on my wall next to my monitor

13:45 makes it a whole lot easier

13:45 sritchie: yup

13:46 http://www.pchristensen.com/slimecommands.pdf

13:46 good stuff there, too, for SLIME

13:50 rhdoenges: sritchie: it must be christmas or something

13:55 mattmitchell: anyone know of a way to remove double quotes from a word using paredit? for example, I want "test" to become test

13:56 sorry, maybe i should go to #emacs :)

13:57 hugod: M-s

13:58 mattmitchell: hugod: awesome thank you

14:03 gfrlog: aw crap never use macros in (deftest) :(

14:03 matthias_: im usign cantor. when i type (vec2 3 3) in the slime-repl, i get [x=3.0, y=3.0]. how does slime get that? when i try to turn a vec2 into a string in my program, i just get the type and the address

14:04 dnolen: matthias_: cantor probably doesn't define toString for vec2

14:05 matthias_: but then how does slime get that string?

14:14 aaelony: hi, I'm making a silly mistake somewhere. I have a map and I see the key exists, but can't access the value of the key... test=> (class (j 0))

14:14 clojure.lang.PersistentHashMap

14:14 test=> (keys (j 0))

14:14 ("a" "b" "c" d" "e" )

14:14 test=> (:d (j 0))

14:14 nil

14:16 gfrlog: aaelony: your keys are strings but you're trying to access keywords

14:16 ({"a" 8 :a 3} :a)

14:16 ,(:a {"a" 8 :a 3})

14:16 clojurebot: 3

14:17 gfrlog: if you need to use strings for keys, you can access them like ((j 0) "d") or (get (j 0) "d")

14:17 aaelony: gfrlog: wow, thanks.

14:17 gfrlog: (strings and keywords are two different but similar things, and both can be used as keys in a map)

14:17 (in fact just about anything can be a key in a map)

14:18 aaelony: thx

14:18 gfrlog: yep

14:19 aaelony: that helps quite a lot :)

14:20 gfrlog: using keywords as keys is more common, but whether you should or not depends on what you're doing

14:20 aaelony: I'm just using what clj-json decided was best. I just couldn't access what I knew it read in.

14:21 gfrlog: ah, I see. I think clj-json has a config option that will convert the strings to keywords for you

14:22 (parse-string s true)

14:22 I'm mildly surprised it doesn't default to that

14:22 amalloy: gfrlog: string literals for unusual objects are easier to construct than keyword literals

14:23 i mean, i think it should default to keywords too. but it's possible to see why they might not

14:23 gfrlog: amalloy: in the context of converting a JSON object to a map?

14:23 I mean...I guess

14:24 you're probably thinking the same thing I was and saying it differently

14:24 jcromartie: imagine if your JSON had spaces in the keys

14:24 keywords = fail

14:24 although

14:25 ,(keyword "this works")

14:25 clojurebot: :this works

14:25 jcromartie: :)

14:25 gfrlog: jcromartie: as does asking the parser to return strings

14:25 jcromartie: yes

14:25 gfrlog: I didn't say they should be incapable of returning strings :)

14:26 aaelony: well, I'm using the clj-json/parse-string s true option, but I have some nesting where I guess I didn't get keywords

14:26 gfrlog: augh

14:26 I've never used that library

14:26 jcromartie: this should just be a generic function

14:27 aaelony: or maybe I messed something else up...

14:28 gfrlog: I just successfully wrote some meta-testing helpers for clojure.test

14:28 jcromartie: (defn keywordify [m] (if (map? m) (into {} (map (fn [[k v]] [(keyword k) v]) m)) m))

14:29 gfrlog: e.g., (should-fail (is (nil? 42)))

14:29 jcromartie: that misses the nested maps though, doesn't it?

14:30 maybe [(keyword k) (keywordify v)]

14:34 aaelony: in my case it seems I've got a mix of a vector then a nested map

14:34 so, map, vector, map

14:36 gfrlog: fun!

14:37 jcromartie: gfrlog: no it doesn't

14:37 but it does miss maps in collections

14:38 like a vector of maps

14:38 gfrlog: jcromartie: how would it do {"foo" {"bar" 12}} then?

14:46 ,(let [keywordify (fn [m] (if (map? m) (into {} (map (fn [[k v]] [(keyword k) v] m)) m)))] (keywordify {"foo" {"bar" 12}}))

14:46 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$map

14:47 jcromartie: gfrlog: it works in that case

14:48 gfrlog: ,(let [keywordify (fn [m] (if (map? m) (into {} (map (fn [[k v]] [(keyword k) v]) m)) m))] (keywordify {"foo" {"bar" 12}}))

14:48 clojurebot: {:foo {"bar" 12}}

14:49 gfrlog: maybe I'm misunderstanding what you were trying to do

14:55 mattmitchell: what's the easiest way to pull out values from a list, where the values returned must be present in another?

14:56 stuartsierra: (filter (set the-other-list) the-first-list)

14:56 scgilardi: certified easiest™

14:57 gfrlog: ,(filter #{false nil true 17} [1 2 3 true false nil "whut"])

14:57 clojurebot: (true)

14:57 gfrlog: sorry I couldn't stop myself :(

14:57 mattmitchell: nice thanks to you both!

14:58 amalloy: gfrlog: that always makes me cry

14:58 gfrlog: amalloy: that the code does that or that I wrote the code?

14:58 amalloy: both i guess

14:58 gfrlog: glad I could help

14:59 Clojure: because the easiest way to do something shouldn't have to work 100% of the time.

14:59 derp_: is there an easy way to comment out highlighted text in emacs?

14:59 jcromartie: M-x comment-region

15:00 amalloy: derp_: M-;

15:00 jcromartie: or that

15:00 derp_: thanks!

15:00 scgilardi: right, you need to be careful if nil and false are possible. or change to using keep and only special-case nil.

15:01 amalloy: or: commit it to git so you won't be afraid to just delete it instead of commenting it out

15:01 manutter: what if your afraid of git tho?

15:01 *you're

15:01 gfrlog: read about git

15:02 amalloy: manutter: there's always room in our nations jails for more dissidents

15:02 gfrlog: if you're afraid of reading, then watch a youtube video about reading

15:02 amalloy: *nation's

15:02 manutter: lol

15:02 rhdoenges: manutter: then use hg. or bzr. or svn. or cvs. anything is better than nothing

15:02 gfrlog: if you're afraid of youtube, then I'll tell amalloy that you're afraid of git and that'll be the end of you

15:03 jcromartie: amalloy: what nation is that?

15:03 not mine

15:03 amalloy: jcromartie: the us, alas

15:03 manutter: I think that would be consternation

15:03 jcromartie: hah hah... no more room

15:03 anyway

15:03 yes, source control is better that commented out code...

15:03 and also, (comment ...) is better than ;;

15:03 if you really want to be slick

15:03 gfrlog: git commit -a -m 'wut this commit is'

15:04 arohner: so I have a large set of strings (11 million). Is there a faster or more memory efficient way to determine if a string is in the set than a normal contains?

15:04 amalloy: jcromartie: ##((fn [x] (inc x) (comment "used to return 2x")) 3)

15:04 sexpbot: ⟹ nil

15:04 arohner: I can't just store the hash codes, because of collisions, right?

15:04 jcromartie: ah, (comment) returns nil?

15:05 amalloy: yes. that is why it is evil and shouldn't be encouraged

15:05 jcromartie: derp!

15:05 I always use it in the top level

15:05 that's why

15:05 amalloy: *nod*

15:05 gfrlog: arohner: contains should be looking up by hash code. I'd think the worst part is that the hash code of your test string has to be computed

15:05 amalloy: it's usually harmless of course

15:05 gfrlog: arohner: and I guess it'll compare them character-by-character as well

15:06 arohner: sounds like I need to read some source

15:06 scgilardi: arohner: a bloom filter could help

15:06 jcromartie: then there is #_

15:06 amalloy: gfrlog: i imagine strings cache their hashes

15:06 jcromartie: scgilardi: the only problem there is that you need more hash functions

15:06 amalloy: since they're immutable

15:06 arohner: amalloy: yeah, I would assume that too

15:06 gfrlog: amalloy: yes

15:06 but there's no reason to assume his string has been cached before

15:06 hashed

15:06 hash-cached

15:07 hached

15:07 amalloy: gfrlog: as soon as it gets put into a hashmap, it has

15:07 gfrlog: amalloy: if he already put it into his set then he doesn't need to check if it's there

15:07 probably

15:07 amalloy: scgilardi: know of a good article on bloom filters? sounds interesting but i don't know anything about them

15:07 scgilardi: jcromartie: right, I was interpreting it as a problem to be solved with 11 million strings rather than specifically about set.

15:07 http://en.wikipedia.org/wiki/Bloom_filter

15:07 jcromartie: how about grep

15:07 mattmitchell: stuartsierra: how the heck does "(filter (set the-other-list) the-first-list)" work?

15:08 jcromartie: that would search 11M strings pretty fast

15:08 ;)

15:08 mattmitchell: ,(doc set)

15:08 clojurebot: "([coll]); Returns a set of the distinct elements of coll."

15:08 gfrlog: mattmitchell: it creates a set, which is a function that will return elements it contains

15:08 mattmitchell: for almost all elements, that corresponds to returning truthy, which is what filter looks for

15:08 mattmitchell: good grief that's slick

15:09 gfrlog: sounds like a bloom filter is like a hash-map that doesn't bother storing values

15:10 or hash-set rather

15:10 arohner: and requires multiple hash fns

15:10 gfrlog: haven't seen that part

15:10 amalloy: scgilardi: that's pretty neat

15:11 arohner: gfrlog: it's in the second sentence of the wiki article

15:11 requires k distinct hash fns

15:11 gfrlog: arohner: yep found it. Okay I take it back this is totally different and also clever.

15:12 * amalloy thinks Bloom Filter sounds more like something you'd use in photoshop

15:12 gfrlog: I would join a band by that name.

15:14 "Unlike sets based on hash tables, any Bloom filter can represent the entire universe of elements."

15:15 amalloy: gfrlog: (constantly true)

15:15 gfrlog: okay fine

15:17 I guess you can represent cofinite sets as well...

15:17 mattmitchell: how can i extract the values from a hash-map, using a list of keys? For example, {:one 1 :two 2 :three} -- I want the values for :two and :three

15:17 jcromartie: I wonder... how big would your bloom filter have to be for an 11M item set

15:17 gfrlog: mattmitchell: (map m my-keys)

15:17 mattmitchell: i know this is gonna be simple

15:17 there you go :)

15:17 thanks

15:17 gfrlog: yessir

15:18 I would say for whathisface's application, if he can't tolerate false positives then the bloom filter won't do any good

15:18 since he'd have to compute a bunch of hashes instead of just one

15:19 save some space though I guess

15:20 arohner: gfrlog: saving space would be nice, right now the strings occupy 1.5GB. I'm more interested in speed than space though

15:21 gfrlog: arohner: I guess the bloom filter would help you filter out the negatives. Are your strings long?

15:21 arohner: gfrlog: not really. They're wikipedia article titles

15:21 amalloy: arohner: if you have them in a set already, looking them up will be fairly fast, i think

15:21 arohner: amalloy: but I want moar speed :-)

15:21 amalloy: the set will keep growing itself to limit collisions

15:22 or at any rate, j.u.HashMap does. i haven't read the impl for clojure's, but i imagine it has similar guarantees about the load factor

15:22 gfrlog: get a real big CPU that has 2 GB of on-chip cache

15:23 * gfrlog goes off to build such a thing and market it as "GPUs for hash-maps"

15:25 edw: Anyone out there using aleph? I'm getting a hang when I wait on respons from my redis server.

15:25 amalloy: edw: (a) what version of aleph redis, (2) what commands are you sending?

15:28 jcromartie: arohner: maybe another option would be a tree

15:29 amalloy: jcromartie: that will be way slower than a hashset

15:29 gfrlog: a tree based on prefixes maybe?

15:29 jcromartie: right

15:29 derp_: how does one append to a vector?

15:29 gfrlog: derp_: conj

15:29 arohner: clojure sets are already tries on the string's hashcode, right?

15:29 amalloy: &(conj [1 2] 3)

15:29 sexpbot: ⟹ [1 2 3]

15:29 gfrlog: amalloy: dang that was fast

15:30 arohner: probably so

15:30 amalloy: gfrlog: i have six fingers on my right hand

15:30 derp_: why does conj prepend when used with lists?

15:30 sritchie: amalloy: I know a guy who's been looking for you

15:30 derp_: &(conj [1 2] 3)

15:30 sexpbot: ⟹ [1 2 3]

15:31 amalloy: derp_: it adds in whatever manner is most efficient for the underlying type

15:31 gfrlog: amalloy: dang that was fast

15:31 I'm gonna stop reading questions

15:31 or at least wait 5 secondns

15:31 amalloy: *chuckle*

15:32 derp_: okay, well I am using this function called 'butlast', but it returns the modified vector's contents as a list

15:32 how do I change that behavior?

15:32 amalloy: derp_: no, it returns it as a lazy-seq

15:33 (which happens to print the same as a list)

15:33 * gfrlog dangs it

15:33 amalloy: derp_: use subvec instead if you want a vector

15:33 &(doc subvec)

15:33 sexpbot: ⟹ "([v start] [v start end]); Returns a persistent vector of the items in vector from start (inclusive) to end (exclusive). If end is not supplied, defaults to (count vector). This operation is O(1) and very fast, as the resulting vector shares structure with the original and no trimming is done."

15:33 gfrlog: woah

15:33 I wonder how often I've missed that :/

15:34 &(doc supervec)

15:34 sexpbot: java.lang.Exception: Unable to resolve var: supervec in this context

15:36 amalloy: gfrlog: i was sad to find out that subvec throws an exception on negative offsets

15:36 gfrlog: haha

15:36 derp_: amalloy: thank you very much

15:36 amalloy: &(-> [1 2 3] (subvec 1 3) (subvec -1 3)) ; wish this returned [1 2 3]

15:36 sexpbot: java.lang.IndexOutOfBoundsException

15:36 edw: amalloy: redis 2.2.10 and I'm sending PING, AUTH, stuff like that. The basics...

15:37 gfrlog: oh that'd be terrible

15:37 derp_: one last q, how would you have known that butlast returns a lazy-seq if you were unfamiliar with clojure?

15:37 gfrlog: ,(class (butlast (range 20)))

15:37 clojurebot: clojure.lang.PersistentVector$ChunkedSeq

15:37 amalloy: edw: i was terribly unclear. what version of aleph?

15:38 gfrlog: derp_: well maybe that didn't help, but most functions return lazy seqs if there's no particular reason to do anything else

15:38 edw: 0.2.0-alpha2

15:38 amalloy: edw: he fixed a similar issue for me in 0.2.0-alpha3: http://groups.google.com/group/aleph-lib/browse_thread/thread/60e02641dbaa05fe

15:38 derp_: so it's the default return type for most list/vector manipulation stuff?

15:38 amalloy: derp_: yes

15:39 edw: Ah, didn't know there was an alpha 3...

15:39 amalloy: edw: i think it's still a snapshot

15:39 this was like a week ago

15:39 gfrlog: derp_: clojure's designed to encourage you to deal with lazy seqs whenever you can

15:39 edw: amalloy: Is it up on clojars? 0.2.0-alpha4-SNAPSHOT?

15:39 Err, 3.

15:39 amalloy: yes

15:40 gfrlog: like ##(zipmap (range 5) (repeat 0))

15:40 sexpbot: ⟹ {4 0, 3 0, 2 0, 1 0, 0 0}

15:40 edw: There we go! Thanks, amalloy. Let's see if this works...

15:41 jcromartie: trie functions yay

15:41 probably too slow for 11M strings

15:41 https://gist.github.com/1045515

15:41 but too elegant to pass up :)

15:42 gfrlog: jcromartie: another way to make it go faster is to only use 11 strings instead of 11M

15:42 jcromartie: that's a great idea

15:42 why doesn't everybody just do that?

15:42 gfrlog: ,(let [str-set (set (map str (range 11)))] (time (contains? str-set "7")))

15:42 clojurebot: "Elapsed time: 0.019 msecs"

15:42 true

15:42 gfrlog: can't beat that

15:43 jcromartie: now that I bring that up, what's the access time for your big set?

15:43 edw: amalloy: Still not working (on localhost with 2.2.10 and alpha3-SNAPSHOT). Durn.

15:44 jcromartie: my what? it was arohner's problem

15:44 gfrlog: jcromartie: ah whoops sorry :)

15:45 jcromartie: dammit rlwrap/REPL... why does C-y (yank) send it to the background?

15:45 arohner: gfrlog: I have a document, I want to find all wikipedia titles in the doc. It takes ~700ms right now

15:45 * gfrlog thinks "jcromartie" looks like "arohner"

15:45 amalloy: jcromartie: O(log32(n)) is not much slower than O(1) - the size of the set isn't going to matter much

15:45 gfrlog: amalloy: the caching level will matter

15:46 L1 cache vs. swap matters :)

15:46 jcromartie: so then it's solved? (use a set)

15:46 edw: amalloy: There's some promising stuff in the new branch on github. Might try that.

15:46 amalloy: gfrlog: granted. but he shouldn't be going into swap, and fitting it into cpu cache is impossible regardless

15:46 gfrlog: unless he takes my suggestion of using 11 strings

15:46 or wait

15:47 O(1) was regarding the trie functions?

15:47 amalloy: yes

15:47 gfrlog: sorry, sometimes I get lost in my own stupid side comments

15:48 I'll go make an 11M string set and see how it performs

15:48 jcromartie: I can't even *make* an 11M string set

15:49 I gave up after letting it churn

15:49 for 2 minutes

15:49 gfrlog: jcromartie: how much memory?

15:49 jcromartie: 1024

15:49 (def bigset (set (map str (range 11000000))))

15:49 choffstein: Freaking tomcat. Doesn't play nice with compojure ... seems that when you do your routes in compojure, they are absolute and when you upload your application to tomcat, you get a context in your route (e.g. localhost:8080/myApp/) -- which means all my routes get prefixed with myApp and hence NOTHING MATCHES on compojure. Aaaarrrrrggghhhhh!!! *slams face against keyboard*

15:49 arohner: I have 4GB on this machine, and it takes 2.5GB to load the strings out of the DB, and 1.5GB steady state

15:50 takes about 10 minutes to load them all

15:50 dpritchett`: choffstein, your dev routes don't match your production routes?

15:50 jcromartie: choffstein: can you handle that with middleware?

15:50 * gfrlog just rand jcromartie's code

15:50 jcromartie: arohner: yeah, not surprising I guess

15:50 gfrlog: jcromartie: that expression returned for me after about 15 sec

15:51 `top` puts the jvm at about 23.6% right now

15:51 I think I have 8G?

15:51 jcromartie: gfrlog: weird

15:51 choffstein: ...I can?!

15:51 jcromartie: hm

15:51 choffstein: routes are just functions

15:51 gfrlog: user=> (time (contains? bigset "48482"))

15:51 "Elapsed time: 0.036596 msecs"

15:51 jcromartie: you should be able to wrap them

15:52 not really "middleware" but something to "massage" the request URL

15:52 amalloy: jcromartie: that's middleware :P

15:52 choffstein: dprichett`: the issue is, I have my routes like "/portal", but when I deploy to tomcat, the routes are like "/myApp/portal"

15:52 jcromartie: yeah I was going to say

15:52 :)

15:52 choffstein: Yeah. It's a tomcat issue though. I'm trying to see if I can just deploy the application to / ... but tomcat doesn't seem to like me doing that at the moment :D

15:53 amalloy: (defn without-prefix [prefix handler] (fn [req] (handler (update-in req [:uri] #(s/replace % prefix "")))))

15:54 choffstein: just wrap your outer-level route in something like that, and it will strip the leading "/myApp" before giving it to the rest of your code

15:54 choffstein: amalloy: that is my last ditch idea. seems "hacky" to me.

15:54 gfrlog: amalloy: and then parse the html that comes out and add it back to all the <a>'s?

15:54 amalloy: gfrlog: ouch

15:55 gfrlog: I guess you can do relative paths that avoid that?

15:55 amalloy: gfrlog: yeah but not always

15:55 choffstein: yes, you should probably be able to configure tomcat to do that for you, i guess

15:55 gfrlog: jcromartie: I made another set with longer strings (~25 chars) and it took a few minutes

15:56 choffstein: tomcat lets you deploy an app as the root app

15:56 jcromartie: I've got a lot of stuff going on with my 4G machine... VMWare, Chrome, iTunes

15:56 choffstein: gfrlog: I'm trying to figure that out :)

15:56 jcromartie: 4GB

15:56 gfrlog: choffstein: I think if you upload it as ROOT.war it'll do that automatically

15:56 choffstein: re-he-he-heaaalllyyy?

15:56 gfrlog: choffstein: ma-ha-ha-haaaaaby

15:57 choffstein: IT'S ALIIIVVVEEEE


15:57 gfrlog: using 11M big strings wasn't much slower than 11M little strings

15:58 not only that, 11M big strings was only 1 or 2 times slower than 11 strings.

15:58 unless contains? is returning some kind of lazy boolean

16:00 choffstein: gfrlog: thank you so much. ROOT.war did the trick.

16:00 gfrlog: choffstein: no probalo

16:00 I hate trying to figure out how to make tomcat do stuff

16:01 edw: D'oh. Nothing's working here, amalloy.

16:01 arohner: gfrlog: I assume the big strings aren't much slower, because you only have to deal with the length when you get a hash collision

16:02 ibdknox: How many of you guys would be interested in a datastore backed by redis that mimicked clojure's datastructures:

16:02 arohner: and then you only need to compare strings until you find a mismatch

16:02 ibdknox: (def x (redis-atom {}))

16:02 (swap! x assoc :r 3)

16:02 amalloy: edw: sorry bro

16:02 jcromartie: ibdknox: sounds like the perfect interface to a data store if you ask me

16:02 especially if it works in a transaction

16:02 gfrlog: arohner: I'd think if the string is present you'd still have to compare

16:02 no_mind: I am writing a macro where I wanta function to be passed. This function should be called if certain conditions are met. My queries are a) should I go with a macro or a define a function b) Is it possible to pass the namespace and function name as a single argument ?

16:02 arohner: gfrlog: yes, but only after the hashes match

16:02 edw: What version of Redis are/were you using?

16:03 no_mind: *function to be passed as argument

16:03 amalloy: 2.0.1

16:03 edw: Whoa, that was a while ago.

16:03 hiredman: I would hope a database would supply something higher level than datastructure operations

16:03 amalloy: no_mind: almost certainly this should be a function

16:03 edw: so far i haven't had to deploy at all; it's just what apt-get put on my dev machine

16:03 ibdknox: hiredman: what do you mean?

16:04 hiredman: even a database has to have an add command ;)

16:04 hiredman: ibdknox: a distributed hash table is not a database

16:04 amalloy: hiredman: i think he only called it a datastore

16:04 no_mind: amalloy: ok, and how about passing function name and namespace as single argument ?

16:04 ibdknox: hiredman: that was one example, take this as another:

16:04 amalloy: no_mind: i don't understand the question. just pass the function itself, don't mess around with names

16:05 ibdknox: (def rlist (redis-atom [1 2 3]))

16:05 (nth @rlist 2)

16:05 basically it's a persistence mechanism for clojure collections

16:06 hiredman: *shrug*

16:06 ibdknox: using the wonderful datatypes in redis

16:06 the point was to judge interest more than anything :)

16:06 * hiredman has none

16:06 no_mind: amalloy: lets say I have a namespace abc and a function in abc xyz. I want to know if ther eis some way to just pass fully qulaified function name like abc.xyz assigle function and then have the function executed ? or should I pass ns and function name as two arguments

16:07 ibdknox: hiredman: I assume you use a SQL variant?

16:07 gfrlog: no_mind: you can pass the function itself without worrying about its name


16:07 hiredman: ibdknox: use for what?

16:07 ibdknox: hiredman: persistence? lol

16:08 hiredman: depends

16:08 scgilardi: the fully qualified name would be abc/xyz

16:09 hiredman: persisting datastructures is neat for little apps, or when you are just starting, but not really useful for larger datasets

16:09 no_mind: gfrlog: the function will not be called under all conditions. Plus the arguments tot he function will be modified before function's execution

16:09 dpritchett`: oh hi ibdknox

16:09 gfrlog: no_mind: none of those things require knowing the function's name

16:09 dpritchett`: i have been enjoying noir this week, thank you

16:10 ibdknox: you're quite welcome :)

16:10 hiredman: so anyone using a key-value store is doing it wrong?

16:10 gfrlog: no_mind: if your function is receiving a function as its argument, it can refer to it by the argument name

16:10 dpritchett`: now i just need to figure out how to nest clojure.contrib.sql/with-query-results with your common/layout and defpage functions

16:10 amalloy: no_mind: look at the map function. it takes a function as argument, and applies it a number of times. or partial, which modifies the arguments to the underlying function. model your solution on those

16:10 dpritchett`: For some reason the correct ordering is eluding me

16:10 hiredman: ibdknox: please don't turn my dismissal of your idea into a debate about nosql

16:11 no_mind: gfrlog: yes it can. But what if the function received is in another namespace ?

16:11 gfrlog: no_mind: (fn [f a b] (if a (f b) "not calling that function")) for example

16:11 ibdknox: hiredman: hm

16:11 no_mind: amalloy: thanks

16:11 gfrlog: no_mind: functions don't belong to namespaces

16:11 derp_: is there an easy way to turn a list of characters into a string?

16:11 gfrlog: no_mind: so it doesn't matter

16:11 scgilardi: derp_: use str

16:11 derp_: I am stuck at (map str (rest "1001"))

16:11 amalloy: derp_: ##(apply str '(\a \b))

16:11 sexpbot: ⟹ "ab"

16:12 no_mind: ok

16:12 ibdknox: hiredman: as you wish.

16:12 hiredman: if I want to persist a datastructure I will most likely pr-str it or serialize it and write it to disk

16:12 Raynes: no_mind: Functions are completely and utterly first class. They are just normal values in Clojure. As normal as a string or an integer.

16:12 jcromartie: relations and invariants FTW

16:12 ibdknox: I was thinking of this more as an interface to redis that looked just like any other clojure code

16:13 maybe that's a better way to think of it :)

16:13 hiredman: but redis is not a clojure datastructure

16:13 gfrlog: no_mind: Raynes makes a good point -- you wouldn't as what namespace your other arguments "belonged to"

16:13 s/as/ask

16:13 sexpbot: <gfrlog> no_mind: Raynes makes a good point -- you wouldn't ask what namespace your other arguments "belonged to"

16:13 ibdknox: there's basically a 1:1 mapping between redis datatypes and clojure's collections

16:13 no_mind: ok

16:13 jcromartie: ibdknox: unfortunately it is only 1:1 as long as the elements of those data structures are compatible

16:14 amalloy: ibdknox: that's rather an overstatement. redis's sorted-sets are a bizarre parody of sorted sets

16:14 hiredman: ibdknox: I doubt that

16:14 jcromartie: so, how would you store {:foo 'bar "bat" (java.util.Date.)}

16:14 pr-str?

16:14 gfrlog: no_mind: if that's not clear, then maybe try writing the code the way you think it should work and we can look at it

16:14 hiredman: jcromartie: are you asking me?

16:14 jcromartie: ibdknox:

16:14 amalloy: they're definitely a useful structure, but they don't really map onto anything in clojure

16:14 ibdknox: yes, the downside is that you can't store types

16:15 jcromartie: there is sorted-set in Clojure

16:15 not sure if that's the same thing

16:15 ibdknox: but that's true of any db

16:15 hiredman: hmmm?

16:15 no_mind: gfrlog: its clear andI am trying the ideassuggested

16:15 ibdknox: and that's fair, the semantics between the two are not identical

16:15 the point would be to make them seem that way, though, I feel the intent of my proposal is now lost and I'll drop the subject :)

16:15 amalloy: jcromartie: i know, but redis's are weird

16:16 ibdknox: amalloy: they really are

16:16 jcromartie: ibdknox: I wouldn't discourage you

16:16 hiredman: I would recommend grabbing an existing clojure redis client and making it nice to use and using it a lot to burn it in over this kind of thing

16:16 jcromartie: Redis is what it is, and that interface sounds good

16:16 at least to me

16:17 gfrlog: I kept wanting to say that vars belong to namespaces, but I don't think that's true. Is there anything that can be properly said to "belong to" a namespace? are they just maps from symbols to vars?

16:17 hiredman: "I like my kitchen, my kitchen has knives, this battle axe is kind of like knife, but awkward to use in my kitchen, so I'll pretend it is a knife"

16:18 like a knife

16:18 ibdknox: lol

16:19 hiredman: next thing you know you don't have a leg to stand on

16:19 amalloy: hah

16:22 jcromartie: I am flabbergasted that every part of this trie implementation is basically a one-liner https://gist.github.com/1045515

16:22 FP FTW

16:23 gfrlog: jcromartie: that is remarkable. therefore it is appropriate that you remarked.

16:25 jcromartie: vs. http://code.google.com/p/trie/source/browse/trunk/trie/src/net/bcharris/trie/TrieImpl.java

16:25 or http://code.google.com/p/typocalypse/source/browse/Trie/TrieNode.cs

16:25 or ...

16:25 you get the idea

16:28 gfrlog: jcromartie: you wrote that code just now?

16:28 bsteuber: come on, it's unfair to compare it to java or c# code :)

16:28 gfrlog: user=> (merge (trie/trie "abc") (trie/trie "abd"))

16:28 {\a {\b {\d {}}}}

16:28 dpritchett: this is by far my favorite part of noir so far ibdknox https://github.com/ibdknox/noir/blob/master/src/noir/server.clj#L8

16:29 gfrlog: oh ha

16:29 I'm using clojure.core/merge :)

16:29 dpritchett: that is sweet behavior i had not expected

16:29 gfrlog: no wonder it don't work

16:29 ibdknox: gotta have a good development experience ;)

16:29 jcromartie: gfrlog: yeah

16:29 ibdknox: throw an exception on purpose some time

16:30 jcromartie: gfrlog: maybe I should use merge instead of merge+

16:30 ibdknox: it highlights the parts of the stack that are in your code, if you have the :ns property set when you start the server

16:30 jcromartie: or merge-trie

16:30 gfrlog: jcromartie: I'm not familiar with the data structure -- if I merge "abc" and "abcd", should it contains? both of them?

16:30 jcromartie: yes

16:30 gfrlog: k, might wanna work on that then :)

16:31 user=> (trie/merge+ (trie/trie "abc") (trie/trie "abcd"))

16:31 {\a {\b {\c {\d {}}}}}

16:31 * gfrlog doesn't THINK he messed up that time

16:32 jcromartie: huh

16:32 works over here

16:32 gfrlog: I'm using https://gist.github.com/1045515

16:32 jcromartie: ah ha

16:32 gfrlog: (search t "abc") => {\d {}}

16:33 jcromartie: yeah I see

16:33 because it's not accounting for the terminator in abc

16:34 aaelony: hi, I like the clj-json library in general, but (clj-json.core/parse-string json true) is returning strings instead of keywords for nestings of vectors and maps.

16:34 The following (from earlier) helps a little bit: (defn keywordify [m] (if (map? m) (into {} (map (fn [[k v]] [(keyword k) (keywordify v)]) m)) m)) but not for vectors of maps. How would I locate all keywords and keywordify them even if they are buried in combinations of vectors and maps?

16:35 duck1123: Has anyone here ever experienced an issue where they can upload a small file to their ring app, but a slightly larger file times out?

16:35 jcromartie: gfrlog: I don't think contains? should exist, or it should be (not (nil? (search t s)))

16:35 gfrlog: aaelony: you could add a second clause after (if (map? m)) that checks if it's a collection

16:35 aaelony: I guess it could only be a vector right? so check if it's a vector and if so map it over keywordify

16:35 jcromartie: I like the terminator idea

16:35 duck1123: it gets a bit more complicated with my using aleph and 1.3

16:35 aaelony: i think it will be a vector

16:36 thanks, gfrlog

16:36 jcromartie: aaelony: actually let me rework that keywordify

16:36 gfrlog: jcromartie: so contains? would check if the resulting map has the terminator as an element

16:37 jcromartie: you could even make it all safe by using a unique (new Object) instead of nil or anything else

16:37 ibdknox: duck1123: servers often have upload memory limits

16:37 aaelony: thanks jcromartie

16:37 gfrlog: isn't there a keywordize-keys function somewhere?

16:38 maybe not...

16:38 ibdknox: gfrlog: I think ring actually has one

16:38 amalloy: gfrlog: clojure.walk, i think?

16:38 gfrlog: clojuredocs doesn't return one

16:38 oh but walk does have it

16:39 aaelony: try clojure.walk/keywordize-keys

16:39 aaelony: checking, thanks

16:39 duck1123: wrap-keyword-params

16:39 gfrlog: (dec clojuredocs)

16:39 sexpbot: ⟹ -1

16:39 ibdknox: https://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middleware/keyword_params.clj

16:39 jcromartie: like a boss, gfrlog

16:39 ibdknox: lol

16:40 aaelony: it says "Recursively transforms all map keys from strings to keywords." I wonder if it allows for nestings with vectors...

16:40 gfrlog: aaelony: try it :)

16:40 duck1123: I don't believe it does

16:40 aaelony: looks great

16:40 very nice

16:40 at least for me mangy data structure :)

16:41 s/me/my/

16:41 sexpbot: <aaelony> at least for my mangy data structure :)

16:41 jcromartie: aaelony: it does

16:43 gfrlog: you'll be pleased to know that fixing trie/contains? involved changing two lines

16:44 gfrlog: jcromartie: you'd have to fix trie/trie as well, right? to add a terminator?

16:45 jcromartie: updated https://gist.github.com/gists/1045515/edit

16:45 ibdknox: that link redirects

16:46 we can't edit it ;)

16:46 jcromartie: oops

16:46 herp derp https://gist.github.com/1045515

16:46 ibdknox: that really is impressive

16:46 tries are fun

16:46 gfrlog: jcromartie: ::terminator is gooder idea than (new Object)

16:47 jcromartie: and I even spelled it right (some blub implementation had "Terminater")

16:48 gfrlog: ha

16:48 jcromartie: makes me think of a cybernetic potato for some reason

16:48 * gfrlog likes the blub reference

16:48 jcromartie: is it idiomatic for predicates to return true or false, exactly?

16:48 or is true or nil good enough?

16:49 gfrlog: jcromartie: considering the sorts of things that people use for predicates, I'd say you can return any dang thing you want :)

16:49 jcromartie: hah

16:49 our database uses -1 for true

16:49 0 or NULL for false

16:49 fun times

16:49 gfrlog: that's fantastic

16:50 if I want to restrict a predicate I just pass it through (boolean) at the end

16:52 jcromartie: ah

16:52 good idea

16:53 I was reading this today http://dev.clojure.org/display/design/Library+Coding+Standards

16:53 pretty good advice in general

16:53 dpritchett: is the @ dereference operator in clojureql standard clojure or specific to this library?

16:53 (clojureql.core/table :posts) gives me a sql statement, if i prepend a @ it gives me the results

16:53 Raynes: gfrlog: Or true?

16:53 :D

16:54 gfrlog: Raynes: uhhh...huh?

16:54 * gfrlog is confused

16:54 Raynes: gfrlog: And then pretend that doesn't cause bugs.

16:54 dpritchett: nevermind, found it myself on the clojure docs

16:54 gfrlog: oh okay. I can pretend.

16:55 Raynes: may as well use (not) while we're at it

16:55 boolean is clojure for !!

16:56 amalloy: gfrlog, jcromartie: i prefer (Object.) to ::terminator, fwiw

16:56 jcromartie: amalloy: what's your reason why?

16:56 gfrlog: amalloy: whyso? Isn't it a perfect example of qualified keywords?

16:56 hugod: stuartsierra: I thought the new contribs were all 1.2 compatible - doesn't that imply that they should declare a 1.2 dependency, rather than whatever happens to be the latest release?

16:56 gfrlog: not to mention it's using clojure stuff instead of jvm stuff

16:57 amalloy: jcromartie: it's more general. yes, in practice people won't want to store :my-ns/terminator, but it's silly to make that illegal

16:57 whereas if you use an (Object.) you can guarantee nobody will ever put it in there

16:57 jcromartie: amalloy: there's a problem with (Object.)

16:57 gfrlog: amalloy: when would you ever want to use a qualified keyword outside your own namespace?

16:57 amalloy: gfrlog: plenty of reasons

16:57 jcromartie: and you couldn't really serialize it

16:58 amalloy: jcromartie: that's a fair point

16:58 gfrlog: I say anybody who does such a thing deserves his fate

16:58 bsteuber: everything that's not a char and easy to compare is okey, isn't it?

16:58 gfrlog: also something something about plenty of room in the prisons

16:58 bsteuber: so my favorite would be nil as terminator

16:58 amalloy: bsteuber: ergh

16:59 jcromartie: nil might be a good idea

16:59 assuming you can use nil as a key?

16:59 amalloy: don't use nil as a map key. it's horrible

16:59 gfrlog: but wanting to store seqs with nil is much more plausible

16:59 amalloy: jcromartie: you can, but it's such a cause of problems that even j.u.Collection says it's an optional feature for maps to support, iirc

16:59 jcromartie: hah

17:00 stuartsierra: hugod: Perhaps. For now it's convenient on the build server, and your local dependency should override it.

17:00 bsteuber: ah true, you can use tries for any sequential data

17:00 amalloy: Some map implementations have restrictions on the keys and values they may contain. For example, some implementations prohibit null keys and values, and some have restrictions on the types of their keys. Attempting to insert an ineligible key or value throws an unchecked exception

17:00 bsteuber: so ::terminator or just ::end is best

17:00 gfrlog: or ::__TERMINATOR__ just to be safe

17:01 jcromartie: ::__PRIVATE__*TERMINATOR*__DO_NOT_USE

17:01 gfrlog: maybe with a guid at the end :)

17:01 hugod: stuartsierra: just worried about 1.2 compatability being tested/lost

17:02 stuartsierra: hugod: It's true we need more tests across versions. I have to figure out how best to do that on Hudson.

17:02 But please file bugs if anything is not 1.2-compatible.

17:02 amalloy: jcromartie: and, since i'm on my mini-rant about null keys, clojure.lang.APersistentMap has a .valAt method that looks like: if (hasNullKey) return nullValue; else // do real lookup

17:03 gfrlog: jcromartie: time to box all your keys. 1 more line per function.

17:04 bsteuber: amalloy: good to know, always thought nil is as good as any other value

17:04 gfrlog: ,({nil "tom" :jill "bob"} nil)

17:04 clojurebot: "tom"

17:05 gfrlog: ,(let [m {nil "tom" :jill "bob"}] [(.get m nil) (.get m :jill)])

17:05 clojurebot: ["tom" "bob"]

17:06 amalloy: &(clojure.string/replace-first "test" #"q" identity)

17:06 sexpbot: ⟹ nil

17:07 amalloy: does this seem crazy to anyone else?

17:07 gfrlog: hmmm....maybe not

17:07 since you want to replace exactly one thing, you might be interested to know that it wasn't there

17:08 jcromartie: gfrlog: is there a standard way to box values?

17:08 gfrlog: jcromartie: dunno. I'd stick'em in a vector maybe?

17:08 then use first to access

17:08 amalloy: wait why are we boxing things?

17:08 jcromartie: it looks like a box

17:08 gfrlog: amalloy: so he can have nil keys

17:08 jcromartie: (defn box [x] [x])

17:08 gfrlog: ha

17:09 now make a macro to get rid of that redundancy

17:09 jcromartie: (def box vector)

17:09 (def unbox first)

17:09 amalloy: (defmacro identity-function [name args-and-body] `(defn ~name ~@(repeat 2 args-and-body)))

17:10 jcromartie: I was going to say

17:10 defredundant

17:10 totally worth it

17:10 gfrlog: (defmacro defaboxingfn ...)

17:12 amalloy: so you don't object to having [nil] as a key?

17:12 amalloy: gfrlog: in most circumstances i suspect it's silly, but there's nothing wrong with it

17:12 gfrlog: jcromartie: now that I think about it, list might be better than vector for performance

17:13 I don't know how much ceremony small vectors create. maybe it's nothing

17:14 jcromartie: BTW, there's no unboxing required

17:14 just (map box s)

17:14 for the lookups

17:15 gfrlog: jcromartie: oh right. I guess you never have to return actual values

17:15 edw: amalloy: ARGH! 9920 != 9220. Was tracing through the code looking to see if the port num was actually used by Aleph but after 30 min I noticed I'd continuously fat-fingered the port number.

17:15 gfrlog: edw: no problem, just (binding [9920 9220] ...)

17:16 edw: Doesn't that only work in Fortan?

17:16 gfrlog: :)

17:16 jcromartie: gfrlog: anyway the gist is updated... this was a distraction, even if it was a fun one!

17:17 gfrlog: jcromartie: w00p

17:17 I love how clojars keeps the pushing instructions front and center

17:17 jcromartie: real work is never so interesting

17:17 gfrlog: jcromartie: nope :(

17:18 jcromartie: now I'm off to manually download a file from an un-scriptable Classic ASP app, manually run it through an XSLT parser because the painfully outdated version of MSXML that we rely on is seriously broken, and then manually email it to a client

17:18 * gfrlog winces

17:18 ibdknox: jcromartie: the pain.

17:19 it should be illegal really.

17:19 * gfrlog imagines various kinds of ultra-manual email

17:19 rbuchmann: (inc gfrlog)

17:19 sexpbot: ⟹ 3

17:19 rbuchmann: :)

17:19 gfrlog: three!

17:20 that's my mostest ever

17:20 rbuchmann: quick, someone dec him :-p

17:20 edw: jcromartie: You just described about half of my job. If you get two spreadhseets too close together on any of my coworkers' monitors, they'll automatically start copying and pasting data to and fro.

17:20 amalloy: rbuchmann: the power...is yours!

17:20 jcromartie: hah hah

17:21 rbuchmann: ^^

17:21 jcromartie: at least the conversion I have to do is scripted

17:21 dpritchett: jcromartie what are you scripting it with

17:21 * dpritchett hugs python then hugs ruby too

17:22 jcromartie: just bash

17:23 later y'alls

17:23 gfrlog: bye

17:23 jcromartie: (but I do love me some Rake)

17:23 matthias_: what;s an abstract method error?

17:23 * gfrlog notes that phrase can be parsed two ways

17:24 hiredman: matthias_: often means you are calling an abstract method

17:25 clizzin: hey all, i haven't used clojure with mysql for a few months. last time i checked, clojureql was great for querying but not inserts/updates/connections, clojure.contrib.sql got the job done on those other fronts but wasn't too elegant, and there were some other little libs that aimed to cover both areas but weren't too mature. what's the state of the art now for clojure and mysql?

17:26 gfrlog: clizzin: those first two points are all I know of.

17:31 VT_entity: hey all, I was wondering if you could help me with a tricky error

17:32 gfrlog: VT_entity: continue

17:32 Raynes: ~anyone

17:32 clojurebot: Please do not ask if anyone uses, knows, is good with, can help you with <some program or library>. Instead, ask your real question and someone will answer if they can help.

17:32 VT_entity: (if (<= 0 (count examplelist))

17:32 ;figure out a way to use let instead of an inline def here

17:32 ((conj newlist (+ 1 (peek examplelist))) (def examplelist (pop examplelist))))

17:32 gfrlog: Raynes: I thought of that but he didn't use the word "anyone" :)

17:32 VT_entity: thanks clojurebot, that's not condescending at all.

17:32 Raynes: Still applies. :p

17:32 VT_entity: lol

17:32 gfrlog: VT_entity: he said please at least

17:33 VT_entity: that (<= 0 (count ...)) should always be true right?

17:33 VT_entity: it's giving me "clojure.lang.PersistentList cannot be cast to clojure.lang.IFn"

17:33 amalloy: yes, that's the (( construct

17:34 VT_entity: you mean I have too many parens?

17:34 gfrlog: VT_entity: yes

17:34 amalloy: no

17:34 gfrlog: maybe

17:34 Raynes: inpossible

17:34 gfrlog: always

17:34 VT_entity: hahahaha

17:34 Raynes: impossible, even.

17:34 amalloy: if you *wanted* to do it that way, you need (do (thing1) (thing2)), which is the same number of parens

17:35 but the approach is evil and sinful anyway, as you noted since you came to ask for help

17:35 VT_entity: I thought the do was implied? if evaluates whichever predicate based on whether it's true or false

17:35 amalloy: no

17:36 VT_entity: so I need (if (foo?) (do (bar))

17:36 dpritchett: Quick data manipulation question: How would I turn '({:id 1 :content "hey"} {:id 2 :content "there"}) to [:h1 1][:p "hey"][:h1 2][:p "there] ?

17:36 gfrlog: VT_entity: no (if (foo?) (bar))

17:36 dpritchett: i'm messing with noir and hiccup, trying to turn my simple map into a series of vectors

17:37 VT_entity: that's what I figured, amalloy wants me to use do, but I wasn't sure if I needed it.

17:38 rbuchmann: if bar is several statements, you need do

17:38 gfrlog: dpritchett: ##(mapcat (fn [{:keys [id content]}] [[:h1 id] [:p content]]) '({:id 1 :content "hey"} {:id 2 :content "there"}))

17:38 sexpbot: ⟹ ([:h1 1] [:p "hey"] [:h1 2] [:p "there"])

17:38 amalloy: &(mapcat (fn [{:keys [id content]}] [[:h1 id][:p content]]) '({:id 1 :content "hey"} {:id 2 :content "there"}))

17:38 sexpbot: ⟹ ([:h1 1] [:p "hey"] [:h1 2] [:p "there"])

17:38 * gfrlog wins

17:38 * dpritchett hugs gfrlog, amalloy

17:38 dpritchett: thanks

17:38 gfrlog: amalloy: are those completely identical?

17:38 amalloy: *nod*

17:38 gfrlog: what does this mean???

17:39 amalloy: that i forgot to use juxt

17:39 gfrlog: :D

17:39 lancepantz: hahah

17:39 gfrlog: man we even put the keys in the same order

17:40 amalloy: gfrlog: it's the natural order

17:41 gfrlog: whyso?

17:41 amalloy: because id is first in his example map, and also used first in the desired result

17:41 gfrlog: I guess so

17:41 dpritchett: that function worked first try when i dropped it into my code, thanks again

17:41 gfrlog: and we both used parentheses

17:41 dpritchett: i feel a little dirty now

17:41 amalloy: gfrlog: ?

17:41 * dpritchett reads the mapcat docs five times in penance

17:42 gfrlog: amalloy: nothing

17:42 amalloy: it made no more sense than it appeared to

17:42 VT_entity: oh, you're right, the do fixed the problem. weird. I'm not sure why... also, it only peeks and pops once, which is weird. Any ideas?

17:42 (def examplelist '(1 2 3 4 5))

17:42 (def newlist ())

17:42 dpritchett: i got my mobi/epub copies of Joy of Clojure via email yesterday. i'll dig up :keys again while i'm reading

17:42 VT_entity:

17:42 (if (<= 0 (count examplelist))

17:42 ;figure out a way to use let instead of an inline def here

17:42 (do (conj newlist (+ 1 (peek examplelist))) (def examplelist (pop examplelist))))

17:42 amalloy: VT_entity: https://gist.github.com

17:43 VT_entity: oh, interesting

17:43 gfrlog: amalloy: no way did you type out that entire url with the https before he finished pasting

17:43 amalloy: gfrlog: wtf, of course i did

17:43 gfrlog: gosh dammit

17:43 you've got a bunch of clever emacs doohickeys

17:43 amalloy: gfrlog: using pidgin

17:43 gfrlog: emacs has pidgin now? :P

17:43 amalloy: (i know, right? not hardcore enough at all)

17:45 VT_entity: ok, I just posted it: https://gist.github.com/1045758

17:45 gfrlog: much nicer on the eyes

17:45 next time give it a name that ends in ".clj" and it'll color everything pretty

17:45 VT_entity: oooh

17:46 there we go

17:46 .clj

17:46 Raynes: I don't understand how amalloy can function with Pidgin as an IRC client.

17:46 rbuchmann: wow, what is that supposed to do?

17:46 gfrlog: VT_entity: anyhow, you're not looping at any point, so there's no reason for it to do anything more than once

17:46 hiredman: digusting

17:46 VT_entity: I figured the conditional statement would continue the loop as long as the count of the members of examplelist remains above 9

17:46 rbuchmann: ah, reading descriptions helps :-/ Sorry about that

17:46 VT_entity: 0*

17:47 ah, i'll try to add in recure

17:47 recur*

17:47 gfrlog: VT_entity: look at (loop) also

17:47 rbuchmann: you'll need something to recur to

17:47 (if ...) is not it

17:48 amalloy: Raynes: i know, i risk making myself an outcast just by mentioning it

17:48 VT_entity: aaah I understand

17:48 dpritchett: i'm using xchat on windows

17:48 VT_entity: what if I name the function and make if recur back to itself

17:48 dpritchett: i don't *love* it but it required a tad less manual reading than irssi

17:48 honestly i miss mirc from ten years ago

17:48 rbuchmann: that'd word

17:48 *work

17:48 what are you actually trying to do?

17:48 VT_entity: probably blow the stack, not optimized I guess

17:49 amalloy: i think he's just implementing ##(map inc '(1 2 3 4 5))

17:49 sexpbot: ⟹ (2 3 4 5 6)

17:49 VT_entity: well, my friend and I were talking about whether it's possible to do something like FOR EACH in a purely functional way.

17:49 rbuchmann: ofcourse

17:49 VT_entity: so, we came up with the idea of incrementing each item in a list by one.

17:49 rbuchmann: either (map ...

17:49 or doseq

17:49 amalloy: rbuchmann: doseq isn't very functional

17:50 hiredman: ~people

17:50 clojurebot: max people is 317

17:50 amalloy: &(for [x [1 2 3 4 5]] (inc x))

17:50 sexpbot: ⟹ (2 3 4 5 6)

17:50 rbuchmann: not much worse that recur though :)

17:50 VT_entity: @______@

17:50 dpritchett: oh no, a noir patch?

17:50 VT_entity: oh damn amalloy

17:50 ibdknox: just pushing the latest unstable build

17:50 for those who wish to follow along

17:51 hiredman: ~#7

17:51 clojurebot: 7. It is easier to write an incorrect program than understand a correct one.

17:51 VT_entity: wait, what's the ampersand?

17:51 hiredman: rbuchmann: how is recur not functional?

17:51 amalloy: tells sexpbot to start paying some damn attention

17:51 VT_entity: oooooh

17:52 rbuchmann: in a style kind of way :hiredman :)

17:53 VT_entity: ah, but the for is still kind of a FOR EACH isn't it.

17:53 hiredman: rbuchmann: what does that mean?

17:53 loop/recur is a *functional* looping construct

17:54 rbuchmann: hiredman: of course

17:54 nvm :)

17:57 ibdknox: I think it's more that one should favor higher order functions over loop/recur and so while that *is* functional it's not as steeped in the spirit of functional programming as another solution would be

17:57 *shrug*

17:57 * dpritchett is pleased to discover that [:marquee %] works in hiccup

18:11 gfrlog: ibdknox: loop/recur could be done as a higher-order function. I think it's just harder to reason about than other expressions

18:11 (map) is much easier to understand than the equivalent thing done with loop-recur

18:11 ibdknox: gfrlog: very true

18:12 gfrlog: I should say harder to reason about when there are simpler/other ways of expressing the thing

18:12 certainly sometimes loop is the simplest thing to do

18:12 maybe that was tautological... :(

18:12 ibdknox: haha

18:13 in general, it's true

18:13 that's good enough I think ;)

19:16 matthias_: huh, i tried using swank.core/break, but i couldnt get it to work. got an error "no such namespace: <mynamespace>" when i tried to compile anything. i now reverted all those changes and i still get that error. with the same code that used to work... and it seems like i can compile it when i type (use '<mynamespace>) in the repl...

19:16 wtf

19:30 bsteuber: matthias_: "no such namespace" means you need to require/use the namespace, so this makes perfect sense to me

19:31 matthias_: the namespace is created in the file i'm trying to compile

19:31 bsteuber: hmm ok, that makes less sense :)

19:32 hiredman: matthias_: what do you mean by compile?

19:32 matthias_: C-c M-k

19:32 C-c C-c gives me the same error

19:33 hiredman: C-c C-k

19:33 matthias_: ok, wtf

19:33 tried it again and it works

19:34 hmm, C-c C-k works too.

19:34 hiredman: C-c C-c will try to run the toplevel form under the cursor in the namespace of the file you are in

19:34 it will fail if the namespace doesn't exist

19:34 matthias_: the menu says that's Compile/Load file as opposed to compiel file

19:34 hiredman: (before compiling)

19:34 use C-c C-k

19:34 matthias_: oh

19:35 so it worked later because i had typed (use 'blabla) in the repl and that compiled it?

19:35 hiredman: most likely

19:35 matthias_: so that actually makes sense

19:36 thanks :p

19:36 hiredman: I am not sure what the behavior of C-c M-k is with clojure, because you can't just compile, compiling in clojure is always compile and load

19:37 matthias_: what does compile and load mean?

19:37 bsteuber: I expected the two to be synonymous, but maybe they're not

19:37 hiredman: they are for clojure

19:38 bsteuber: sure, for CL it's different

19:38 matthias_: synonymous? so "compile" doesnt work, but "compile and compile" does? ;)

19:38 hiredman: compile is code generation, load is loading (and running) code

19:38 so, like, for c compiling and loading are very different

19:40 matthias_: so C-c C-k would run a c program after it's done compiling?

19:41 hiredman: C-c C-k is just compile, so it would just compile it to object code or an executable of some kind

19:41 er

19:41 C-c M-k

19:41 C-c C-k would compile and then run it

19:43 jcromartie: so, has Hiccup won? or what?

19:44 I don't hear much about enlive, as powerful as it is

19:44 it seems like Hiccup is easier

19:44 amalloy: jcromartie: i like hiccup. real web developers like enlive

19:44 jcromartie: "Real web developers" huh?

19:44 I am tempted to go with StringTemplate

19:44 hiredman: depends if you are looking for templating or just something better then concating strings

19:45 scottj: jcromartie: ppl other than weavejester :)

19:45 gfrlog: I lost my ability to write <html> when the rails folk switched to haml; so I use hiccup.

19:45 jcromartie: hah, Haml is great

19:45 gfrlog: haml doesn't feel very much like clojure though

19:45 jcromartie: well, it was nice being here

19:45 bye

19:45 :)

19:45 amalloy: jcromartie: eg, brehaut hates hiccup because he can't just open up the html file in his html editor, or even see what the page looks like without starting a clojure webserver

19:46 * jcromartie plays scrabbe

19:46 jcromartie: scrabble

19:46 gfrlog: jcromartie: scrabble

19:46 oh I didn't see the typo; I thought "playing scrabble" had something to do with saying "scrabble"

19:46 so I was joining in

20:28 matthias_: ,(update-in {:test "bla"} [:test] #(%))

20:28 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn

20:28 matthias_: why is that?

20:29 oh it works if i use (fn [s] s). thought that would be the same

20:29 hiredman: ,(macroexpand '#(%))

20:29 clojurebot: (fn* [p1__803#] (p1__803#))

20:30 dnolen: ,(update-in {:test "bla"} [:test] identity)

20:30 clojurebot: {:test "bla"}

20:34 matthias_: i dont understand why #(%) doesnt work

20:34 hiredman: ,(macroexpand '#(%))

20:34 clojurebot: (fn* [p1__808#] (p1__808#))

20:34 matthias_: yeah i saw that

20:35 hiredman: well, there you go

20:35 matthias_: doesnt tell me anything :p

20:35 hiredman: uh

20:35 you can read the code right?

20:36 matthias_: i dont know what fn* is. looks like its calling its argument though. which is strange. cause i dont think its supposed to

20:36 hiredman: ,(macroexpand '(fn [x] x))

20:36 clojurebot: (fn* ([x] x))

20:36 hiredman: that is exactly what #() is

20:38 matthias_: i must have learned that wrong... but i've been using that # syntax for a while now... ;) (still a clojure newb though)

20:38 hiredman: if that is not what #() is, what would #(str %) expand to?

20:39 matthias_: oh

20:39 dnolen: ,((fn [x] x) "foo")

20:39 clojurebot: "foo"

20:39 dnolen: ,((fn [x] (x)) "foo")

20:39 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn

20:39 hiredman: if #(%) expanded to (fn [x] x) then #(str %) would be (fn [x] str x)

20:40 hardly seems useful

20:41 amalloy: matthias_: fwiw, what you meant by #(%) is just identity

20:50 seancorfield: interesting. what've you changed in congomongo?

20:53 seancorfield: added 1.3 support

20:54 the owner of the congomongo group on clojars seems to have gone awol and i need it in a repo since i'm starting to share it with my team

20:55 every other library we depend on is already in a public repo... except congomongo 0.1.5-SNAPSHOT :(

20:56 ideally, i'd have update permissions on the existing congomongo group on clojars but...

21:00 matthias_: shouldnt lisps have some kind of "close all open parentheses" thing? i mean you often end up with ))))))) at the end of a function...

21:01 dnolen: matthias_: that sort of thing is why people use paredit, or a Lisp-aware text editor.

21:01 seancorfield: most of us use an edit mode that balances parens automatically

21:01 i use eclipse + ccw

21:02 matthias_: yeah i use one too. still dont like it.

21:03 seancorfield: oh, so you mean some magical syntax that means "close all open parentheses"?

21:03 matthias_: yeah

21:03 seancorfield: like... #) ...?

21:03 as an example

21:03 matthias_: yeah

21:04 i'm sure its a bad idea for some reason... ;)

21:04 amalloy: seancorfield: i've heard of some lisps that use ] for that

21:04 but yes, it's a bad idea

21:04 matthias_: why?

21:04 clojurebot: why not?

21:04 seancorfield: amalloy: i had some vague recollection of reading something about that once...

21:04 amalloy: matthias_: it would be so easy to make mistakes when editing the code

21:05 seancorfield: well, for a start () is a form but ((] looks... wrong... and doesn't balance

21:05 amalloy: eg, (defun do-stuff (x) (whatever x]

21:05 then later you decide this should be placed inside a closure, or a CLOS class

21:05 seancorfield: yeah, then you need to balance the parens anyway

21:06 to be honest, i really don't notice the parens these days

21:06 amalloy: seancorfield: and if you forgot, the error messages would likely be pretty bad

21:06 seancorfield: :) yup

21:07 and it's not like lisp / clojure has the best error messages in the first place

21:07 clizzin: what's the best way to deal with configuration information that you want read into the project but don't want in the source code, e.g. database hosts/user/pw?

21:07 for clojure projects

21:07 seancorfield: where would you prefer to keep it?

21:07 matthias_: really? if you had something like ] bla bla), it should be able to tell you exactly what's wrong i think

21:07 clizzin: seancorfield: in something like a yml file

21:07 in project root

21:07 amalloy: matthias_: not so! bla and bla would have compile errors before it got to )

21:07 matthias_: anyway the main thing i'd dislike is the way it makes later editing a landmine in all kinds of ways

21:07 seancorfield: so you'd need to read the file at startup...

21:07 clizzin: it would live only on the app server and in dev environment but not in the repo

21:07 yup

21:08 i feel like leiningen supports this somehow, but i don't remember how it's done anymore

21:08 amalloy: but really, what is the *gain* of having ] anyway? you'd still need to stack up ))))) quite often

21:09 seancorfield: we use a clojure map for our configuration ... and so it is in our source code

21:09 amalloy: $google clj-config

21:09 sexpbot: First out of 8100 results is: marklazz/clj-record-blog - GitHub

21:09 https://github.com/marklazz/clj-record-blog

21:10 amalloy: hrm

21:10 well, Raynes wrote a super-lightweight config library. it basically just reads from ./config.clj

21:11 Raynes: It reads from whatever file you want it to. It's just a wrapper around slurping/spitting etc with some convenience functions.

21:11 seancorfield: https://github.com/Raynes/clj-config

21:11 Raynes: I wrote it 100 years ago.

21:11 clizzin: haha

21:11 amalloy: Raynes: "basically", in context meaning "whatever i want it to mean"

21:11 seancorfield: may 3rd 2010 was the first commit :D

21:12 clizzin: sounds like i should just do my own thing

21:12 seancorfield: we have all the system configs in one environments.clj file and automatically select the appropriate one, based on hostname, at startup

22:02 dnolen: interesting, parsing with monads can be slow, http://carlo-hamalainen.net/blog/2011/02/11/parsing-with-monads-can-be-slow/

22:04 I'm assuming Parsec has optimizations to get around this, wonder what similarities they have to optimizing DCGs if any.

22:06 Scriptor: reading about the difference between next/more here

22:06 clojurebot: Cool story bro.

22:07 Scriptor: so basically, calling seq() on a sequence forces the evaluation of the first element of that sequence?

22:07 dnolen: Scriptor: yes

22:11 Scriptor: aha

22:24 amalloy: Scriptor: the ISeq interface has methods first() and rest(). because nil can be stored in a sequence, first() can't return nil to indicate "no elements"

22:24 so instead, functions that return an ISeq (such as clojure.core/seq) must force the first element *just to see if it exists* in order to decide whether to return an ISeq or nil

22:25 there would be other problems, like even-harder nil-punning, if ISeq objects could say "nope! no elements here!" but that strikes me as the main one

22:30 * gfrlog has no idea what amalloy meant by "nil-punning"

22:31 amalloy: gfrlog: in common lisp: (defun count (seq) (if seq (1+ (count (cdr seq))) 0))

22:31 gfrlog: doesn't work in clojure, because empty seqs evaluate to true

22:32 the "pun" is treating an empty sequence as false

22:33 gfrlog: I guess I cdr get it...

Logging service provided by n01se.net