#clojure log - Dec 19 2010

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

0:41 GOSUB: Clinteger: it will seem right.

1:20 TakeV: Does anyone here use Penumbra?

6:46 bartj: what would be the best way to remove nil, empty values from a hash-map

6:49 my attempt is this: (map (fn [[k v]] (if (and v (> (count v) 0)) [k v] nil)) x)

6:51 mduerksen_: bartj: (apply conj {} (filter (comp not nil? val) x))

6:52 map wouldn't give you a sequence, not a hash-map

6:52 *would*

6:53 bartj: mduerksen_, oops, I forgot to give a (into {}...) here

6:53 mduerksen_: ah, you want to remove empty collections as well?

6:54 then my solution won't be complete

6:54 bartj: I'll just use a pos? as well :)

6:54 _ato: (zipmap (keys m) (filter seq (vals m)))

6:54 assuming all the values are collections

6:55 bartj: I sometimes tend to avoid zipmaps, I don't know why

6:57 _ato: (into (empty m) (filter #(seq (val %)) m))

6:57 mduerksen_: _ato: seq is a great idea - but the zipmap code won't work because it interleaves the wrong keys with the values that are left

6:58 _ato: mduerksen_: ah of course. Silly me.

7:00 mduerksen_: _ato: hmm, you're empty is nice, by the way. i should start using it since it does work for all kinds of collections

7:02 _ato, bartj: the most elegant way IMHO would be: (into (empty m) (filter (comp seq val) m)) (i try to avoid the #-notation whenever possible)

7:03 bartj: ok guys, lots of thanks

7:04 * _ato tries to avoid the comp-notation whenever possible >.>

7:05 mduerksen_: _ato: :D really? why?

7:09 _ato: A knee jerk reaction to overuse of pointfree style, I guess. I dunno. ;-)

7:12 Chousuke: avoiding #() is silly.

7:13 pointfree style in clojure becomes unreadable beyond the simplest cases :P

7:19 mduerksen_: hmm, i have heard the term "pointfree" here and then, but i don't actually know what it means. i find (comp seq val) very readable. just to be clear: i'm not forbidding myself to use #(), but i do think that often enough it's a sign that i haven't written my code very idiomatically

7:24 _ato: the terminology was probably made popular by Haskell where it's used much more often than Clojure: http://www.haskell.org/haskellwiki/Pointfree

7:26 essentialy just means combining functions with things like comp and partial and juxt so as to avoid local bindings

7:29 mduerksen_: i see, thanks. i for my part like partial, comp, complement etc., but i agree that this can be overdone (as almost everything)

7:47 LauJensen: mduerksen_: Did you see the slides from cgrands talk at Clojure Conj? If not, you should check them out

7:51 mduerksen_: LauJensen: no, i haven't. are they on slideshare?

7:51 LauJensen: mduerksen_: http://lmgtfy.com/?q=cgrand+slides+clojure+conj&l=1

7:54 mduerksen: LauJensen: sorry, my connection broke. did you write something while i was gone?

7:55 LauJensen: mduerksen_: http://lmgtfy.com/?q=cgrand+slides+clojure+conj&l=1

7:55 just the link

7:55 mduerksen: thanks

7:55 LauJensen: np

8:21 FireSnake: my Clojure app works perfectly on Jetty at localhost:8080 but I get 500 errors on Google App Engine. Anyone guess why?

8:34 Lajla: the stupid part about point free is that it doesn't exist.

8:34 f x y = whatever in haskell is just sugar for f = \x -> (\y -> whatever)

8:34 Also point free tada.

8:35 Alternatively, f . g is just sugar for \fuckThisShit -> (f (g FuckThisShit))

8:51 pyrtsa: ...With the difference that when you write "\x", you are expressing the "point" you are operating on.

9:27 mduerksen: LauJensen: those slides are really insightful. i assume you were referring to my question yesterday?

9:34 leif-p: Hi, where do I report bugs/request enhancements for clojure?

10:42 LauJensen: mduerksen: yes

11:12 ohpauleez: Raynes: Can you play with the new clj-github changes and then when you feel solid, push a new drop to clojars?

11:14 dsop: hmm is there a nice way to validate email addresses in clojure? I only find some Java EE stuff to do it

11:19 fliebel: dsop: You mean just a nice regex?

11:40 leif-p: Is it just me, or is clojure's 'gensym' a little too liberal about its input?

11:41 fliebel: leif-p: How do you mean liberal?

11:42 leif-p: Unlike CL's, which essentially only takes strings, clojure's seems to take any old thing that can be 'str'ed.

11:42 fliebel: &(gensym :test)

11:42 sexpbot: ⟹ :test27260

11:43 stuartsierra: symbol-generating fns are generally liberal in Clojure

11:43 fliebel: &(type (gensym :test))

11:43 sexpbot: ⟹ clojure.lang.Symbol

11:43 stuartsierra: whether or not this is a good thing is a much-debated but never-resolved topic

11:43 fliebel: A symbol that starts with a colon is weird though.

11:45 leif-p: Is there a way to print this in a way that could be re-read? Like CL's |:weird + symbol|.

11:45 stuartsierra: leif-p: not right now, but also debated in the past

11:45 There's ambivalence about whether Clojure symbols should be allowed to contain arbitrary characters.

11:46 In CL it's a leftover from before Lisps had a String type.

11:46 fliebel: stuartsierra: Any idea what came of the escaping discussion? It was related to the |syntax| I think.

11:46 stuartsierra: There was no resolution as fas as I know.

11:48 fliebel: I liked the idea of r"raw strings" like in Python, or unicode quotes, and in case of emergency(huh?) even arbitrary delimiters.

11:49 leif-p: fliebel: Maybe this is the wrong room to say you liked a perl feature :)

11:52 fliebel: leif-p: I ultimately think that if you want wrid shit in your strings, you should read them from a file. And Perl is for emergencies. Like the way Haskell uses Perl to bootstrap Haskell to new platforms by fumbling with the generated assambly.

12:34 TakeV: Is there a way to save work done in a REPL to the namespace you are working in? The REPL makes it easy to test things, but changes don't stick unless I go back and add the changes to the file manually.

12:44 bortreb: Can you call an object created by defrecord in clojure using non-java-legal characters with java in some way?

12:44 chouser: bortreb: probably via reflection

12:44 TakeV: when you define a function at a standard repl, the source code isn't saved anywhere, so no.

12:45 TakeV: one could make a repl that saved things out to a file as you go along or something, but I think most people end up writing their code in a file and then either sending it from there to the repl,

12:45 or saving the file to disk and then reloading it from the repl.

12:46 TakeV: Ah, is there a way to automatically reload a file?

12:46 chouser: hm, not sure about automatically. Some of the IDEs may have that, and such a thing could be written.

12:47 * TakeV nods

12:47 chouser: lazytest has a "watch" mode that reruns appropriate unit tests when it sees a file has been written to disk.

12:47 I usually just push the up arrow in my repl to recall the (use foo :reload-all) line, and then hit enter.

12:47 TakeV: I think I'll write an auto-reload thing.

12:51 bartj: If a clojure file has a "main" method defined, can't I use the functions defined in it?

12:51 KirinDave: bartj: Defined inside the main method?

12:51 bartj: Or just the module containing the -main defn?

12:52 bartj: KirinDave, the latter

12:52 KirinDave: bartj: THen the answer is yes, absolutely

12:53 bartj: I did a ( :use, :only ) with no luck

12:53 KirinDave: Perhaps a gist.github.com demonstration of you problem is in order, bartj

12:56 bartj: KirinDave, unfortunately I can't :(

12:57 KirinDave: bartj: So one of two things is happening here. I'll list them on a probability gradient, high to low:

12:57 bartj: but, I think I am doing a recursive "use"

12:57 KirinDave: recursive use?

12:57 So two modules sharing required code?

12:58 bartj: Module A has func1, func2

12:58 Module B has func3, func4

12:58 KirinDave: Does it actually give you an error for this?

12:59 bartj: weird thing is it runs, but doesn't compile

12:59 am using "ant"

12:59 KirinDave: Yeah, so...

12:59 That may not work. :)

13:00 But without a clear example it's reeeeaallly hard to diagnose.

13:00 bartj: the function calls are like this: func1 -> func3 -> func2

13:00 with the appropriate use/require in place

13:01 KirinDave: Well, first.

13:01 bartj: so, I think there is something wrong with the code organization

13:01 bortreb: TakeV: I've already written an automatic reload function if you're interested

13:02 also, with reagards to my earlier question, I've already taken all the necessary steps to AOT the clojure. i have a class called literally "clojure-object.class" -- note the hyphen. Is there any way to call that from java?

13:05 TakeV: bortreb: I would be very interested.

13:18 bortreb: TakeV: I'll put it on github... hold on

13:22 TakeV: https://gist.github.com/747559

13:23 the idea is you can just call rlm.rlm-commands/re to do a fast reload

13:23 TakeV: bortreb: Thank you.

13:23 bortreb: or (rlm.rlm-commands/reload) to do a very trough reload

13:23 there's also an undef function which does about what you'd thing

13:23 you're welcome!

13:25 so, anyone know if you can call classes like "clojure-object.class" from java?

13:42 shortlord: How can I use partition to create vectors?

13:42 I am using this line:

13:42 (def fields (vec (partition 2 (interleave numbers resources))))

13:49 raek: shortlord: (def fields (map vector numbers resources))

13:49 fliebel: shortlord: (map vector (partition 2 seq))

13:49 maybe

13:49 raek: no need to interleave them and then split them again

13:49 fliebel: oh right :)

13:49 raek: ,(map vector [1 2 3] [:a :b :c])

13:49 clojurebot: ([1 :a] [2 :b] [3 :c])

13:50 shortlord: raek: oh cool, thx :)

14:05 dsapala: anyone know anything about the clj-http project?

14:12 fliebel: the_shadow_of_dsapala: yes

14:14 dsapala: Are any of you folks familiar with clj-http?

14:14 fliebel: yes

14:15 But that doesn't mean it's me, and it doesn't means anyone knows the answer to your question, therefore I suggest you just ask your question.

14:17 dsapala: How can I set a timeout for connections or reads using clj-http?

14:33 fliebel: LauJensen: How are plans for the Reddit clone based on "new" stuff?

14:33 LauJensen: fliebel: Plans are: As soon as I have an hour or two, I'll write it up :)

14:34 fliebel: LauJensen: I'm curious :) I have some plans for a project like this as well.

14:35 LauJensen: I'll make sure to announce it on Twitter :)

14:35 * fliebel checks if he follows LauJensen

14:35 bhenry: how do i assoc into a vector but i want it to be an "insert before" rather than a "replace what's there".

14:36 fliebel: bhenry: I think you'll have to do split-at and concat.

14:37 bhenry: Or do a zipper.

14:39 bhenry: thanks. i decided it was easier to pass what i want into the function that makes the vector.

15:03 currentB: what's the best way to assoc a new key in a hashmap stored within a vector in a dosync?

15:05 AWizzArd: currentB: what code do you currently use so far?

15:09 fliebel: currentB: Cant you just do (update-in vec [index :key] some-fn)?

15:09 &(update-in [1 2 3] [1] inc)

15:09 sexpbot: ⟹ [1 3 3]

15:10 currentB: alright cool thanks, checking that out

15:16 fliebel: Why can't I do this? (dissoc [1 2 3] 1)

15:18 ducki2p: fliebel: dissoc requires a map

15:18 fliebel: In most other ways, vectors seem to be like maps with integer keys.

15:20 &(vals (dissoc (into (sorted-map) (map-indexed vector [:a :b :c])) 1)) ; evil

15:20 sexpbot: ⟹ (:a :c)

15:21 ducki2p: &(vec (filter #(not= 1 %) [1 2 3]))

15:21 sexpbot: ⟹ [2 3]

15:21 fliebel: ducki2p: You remove a value, not an index.

15:46 tomoj: huh, #(not= 1 %) is shorter than (complement #{1})

15:47 #\ is available

15:47 #\{1} ? :)

15:48 nah

15:48 just (remove #{1} ..)

15:54 amalloy: tomoj: #(not= 1 %) can't be nested inside another #() function

15:54 plus, i know it makes me a sinner, but i (def ! complement) in most of my code

17:23 is there any particular guarantee about order of evaluation in a form like [(foo) (bar)]? i'm doing some interop and foo affects some state that bar depends on; is the above sufficient, or do i have to make bar a function of foo in order to make sure foo has been computed?

17:23 chouser: they'll go in order

17:23 maps are not guaranteed, I think.

17:24 amalloy: thanks chouser

17:24 a point in favor of clojure that i didn't have to ask this question until i'd written clojure for about five months

17:24 Raynes: (inc clojure)

17:24 sexpbot: ⟹ 1

17:29 chouser: heh

17:29 nickik: why did you do that raynes? it had no effect on clojure :)

17:29 chouser: scheme doesn't even promise function arguments will be evaluated in order

17:30 Raynes: It does in my little world.

17:30 (inc clojure)

17:30 sexpbot: ⟹ 2

17:30 amalloy: chouser: neither does C

17:30 chouser: !!!

17:30 amalloy: or any of its children (java, etc) as far as i know

17:31 chouser: wow, I had no idea

17:31 brehaut: nickik: presumably because (send clojure inc) or (swap! clojure inc) is long winded ;)

17:32 amalloy: chouser: if you do much imperative programming, http://en.wikipedia.org/wiki/Sequence_point is good reading for the fiddly details

17:32 (4) under <Sequence points in C and C++> in particular

17:33 chouser: I've written a lot of C code in my life, and am surprised this hasn't ever bitten me.

17:33 amalloy: chouser: it rarely does. your functions probably don't affect a lot of global state

17:33 and i think gcc does evaluate them in order, to be nice

17:35 _mst: java does go left to right, just for what it's worth (http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html)

17:35 although it recommends you don't rely on it, which is a bit funny...

17:37 amalloy: _mst: ah, so it does. thanks (15.7.4 for anyone else who's looking)

17:49 can someone load https://gist.github.com/747785 into an editor with paredit mode on? all the parens in my docstring are balanced, and indeed paredit-mode is happy to be enabled, but if i try to do anything interesting (backspace, M-(, etc) in the body of my function, it complains of unbalanced parentheses

17:49 and i'd like to verify it's not something wrong with my config before i file a bug

17:50 (and if i delete the docstring, the problem fixes itself)

17:54 _mst: amalloy: same deal for me here, yep. I notice if I put a space before your {'s in the docstring it's OK...

17:55 amalloy: _mst: aha! well spotted. in fact, any character at all before them is fine; it doesn't like them at the start of a line, apparently

17:56 _mst: it might not be paredit specific... if I do a C-M-a (to go back to the start of the defun) it jumps me to one of those braces

17:56 so maybe clojure-mode is mistaking where the defn actually begins...

17:57 ah! (setq open-paren-in-column-0-is-defun-start nil) seems to fix it for me

17:57 dunno what else it breaks though ;)

17:58 amalloy: _mst: fascinating. thanks

17:59 _mst: heheh no worries

18:02 lpetit: amalloy: works ok with paredit.clj :-p

18:02 amalloy: lpetit: is that for ccw?

18:03 lpetit: amalloy: yeah, pasted your gist into ccw. But don't worry, there are still some corner cases with paredit.clj, your example is just not one of those :-D

18:05 amalloy: I'm currently doing the necessary (albeit boring) port of paredit.clj commands into the new repl client of ccw. Just ported join & split before going to bed

18:08 brehaut: does anyone know if there is an atom-pub lib built on top of ring?

18:29 qbg: How do you get a namespace qualified symbol from a var?

18:31 amalloy: &(apply symbol ((juxt (comp str ns-name :ns) (comp str :name)) (meta #'first)))

18:31 sexpbot: ⟹ clojure.core/first

18:32 amalloy: is kinda disgusting but works

18:32 qbg: &(symbol (subs (str #'first) 2))

18:32 sexpbot: ⟹ clojure.core/first

18:32 qbg: That is worse

18:32 amalloy: lol

18:38 shortlord: given a nested collection that contains a few values, that have to be mutable. Should I place the whole collection in a single ref or rather use separate refs for each value that has to be altered?

18:39 Chousuke: the fewer mutable things you have, the easier they will be to handle.

18:39 so prefer a single ref, unless it becomes a bottleneck

18:41 shortlord: Chousuke: the only problem I have is how to change that single ref with alter. Using assoc-in results in ugly code, because I have to alter the value using assoc-in, which means that I need to dereference the ref directly as the first argument of assoc-in

18:41 which destroys the point of using alter instead of ref-set, right?

18:44 qbg: I'm proud of this: https://gist.github.com/747841

18:46 Something like syntax-rules in Clojure!

18:50 Chousuke: shortlord: hm, no you don't?

18:50 amalloy: shortlord: i don't understand what you're saying

18:51 Chousuke: shortlord: (alter somerefref assoc-in [keys here] val)

18:51 -ref

18:51 shortlord: update-in is useful too

18:54 shortlord: Chousuke: ah ok! I thought that alter provided the ref as the last argument, not the first one

19:00 what would be the best way to increment that value?

19:00 Right now I am using:

19:01 (dosync (alter players (fn [players] (assoc-in players [player resource] (inc ((players player) resource))))))

19:01 but that does not look very elegant

19:03 qbg: (dosync (alter players update-in [player resource] inc))

19:06 amalloy: (inc qbg)

19:06 sexpbot: ⟹ 1

19:06 shortlord: thx a lot :)

19:39 currentB: let's say I have a vector of hash-maps. i will periodically conj a new hash-map to the vector which will just be the "peek" of the vector (ie the first current hash). Occasionally values pairs from this first hash will be chagned or new ones will be added. The lazyness of clojure makes this efficient right? as in a new hash isn't created when each new peek value is conjed to the vector right? or when a new value is assoced in the first

19:40 (i need to implement a simple compiler for a class and I'm wondering if I can just create a new hash-map to represent each scope with the values of all "lower" scopes included, or if it's best to just create a new hash map for each scope and search them sequentially

19:47 amalloy: currentB: i don't understand what you're talking about with "peek". the peek of a vector is the last element in it; if you conj something to a vector it is the peek by definition

19:48 currentB: but if i want to create a new scope, i might want to copy everything in the previous scope to that new scope

19:48 so i can alter those old values

19:48 and just remove it when the scope is exited

19:49 amalloy: oh, you mean if you have like a 10KB hash table, and want to create another one just like it but with one additional item?

19:49 currentB: yes

19:49 i think

19:49 amalloy: you're correct that clojure doesn't copy all 10KB worth of keys, but that's not really related to laziness

19:50 currentB: ok, so that's just the persistence + tricks with pointers?

19:50 amalloy: right

19:50 neither vectors nor hashes are lazy

19:50 mister_roboto1: what is the right way to expose a function that you always want call via memoize? that is, if you are writing a library function and the set of return values is always small so rather than cache it yourself you want to leverage memoize?

19:51 just def it ahead of time and make the real function private?

19:51 amalloy: mister_roboto1: do you want to memoize recursive calls as well?

19:52 mister_roboto1: amalloy: this function is not recursive

19:52 amalloy: (def myfn (memoize (fn [args] (compute))))

19:52 is a solution that works and doesn't seem too ugly to me

19:52 mister_roboto1: ahh, internally make it anonymous. i like it

19:53 amalloy: another useful trick is (def ^{:arglists '([args])} myfn (memoize...))

19:53 so that (doc myfn) and eldoc will be useful

19:54 mister_roboto1: amalloy: that second thing is totally new to me. i'll have to read up on that one.

19:55 currentB: amalloy: ok so if I have a vector x [{:a 1 :b 2}] I can later alter it to (conj x (peek x)), or [{:a 1 :b 2}{:a 1 :b 2}], then later alter just the first hash so it is [{:a 1 :b 2 :c 3}{:a 1 :b 2}], this is better than just structuring things so I have [{:c 3}{:a 1 :b 2}], and then, if I need to find :a, first looking through the first map, then checking the second, etc?

19:55 amalloy: mister_roboto1: ^{key value} is how you attach metadata to a var (or to anything): ##(-> first var meta :arglists)

19:55 sexpbot: ⟹ ([coll])

19:57 raek: with defn, you can also put a map after the docstring (or after name if there is no docstring). the metadata will be merged with that map

19:57 ,(doc defn)

19:57 clojurebot: "([name doc-string? attr-map? [params*] body] [name doc-string? attr-map? ([params*] body) + attr-map?]); Same as (def name (fn [params* ] exprs*)) or (def name (fn ([params* ] exprs*)+)) with any do...

19:57 amalloy: currentB: i think that depends on the performance characteristics of your application. how big the hashes will be, how often they'll change, and so on

19:58 my inclination is to search maps sequentially because it feels like a better description of how nested scopes behave, and especially if the values in the hashes can change you don't want to have to ripple through to all parent scopes

19:59 currentB: ok sweet, that actually seems really obvious now that you put it that way, thanks a ton!

20:00 this room is the great, it solves all my clojure struggles :)

20:24 shortlord: is there any way to alter all the leafs in a nested ref structure? I have a hash-map in a ref vector and I need to change the hash map for every entry in the vector

20:25 amalloy: shortlord: like (ref [{:foo 1} {:bar 2}])?

20:26 shortlord: amalloy: no, rather like [[:key1 {:foo false}] [:key2 {:foo false}]

20:26 and I want to set every :foo to true without changing the keys :key1 or :key2

20:27 there is only one entry in the vector supposed to be {:foo true}, so it would also be ok to find this entry and then selectively switch that to false

20:28 amalloy: &(map #(assoc-in % [2 :foo] true) [[:key1 {:foo false}] [:key2 {:foo false}]])

20:28 sexpbot: ⟹ ([:key1 {:foo false} {:foo true}] [:key2 {:foo false} {:foo true}])

20:28 amalloy: whoops

20:28 &(map #(assoc-in % [1 :foo] true) [[:key1 {:foo false}] [:key2 {:foo false}]])

20:28 sexpbot: ⟹ ([:key1 {:foo true}] [:key2 {:foo true}])

20:29 amalloy: shortlord: like so?

20:29 shortlord: amalloy: that could work, I'll try that

20:29 thx

20:30 currentB: one more thing, using map on a seq will always process the seq in order right?

20:31 amalloy: currentB: yes. as long as the seq has some notion of order; for example, hash-maps don't

20:32 currentB: k

20:34 amalloy: even for non-ordered seqs, you're guaranteed (i think?) that if you iterate over an identical seq N times, it will always be in the same order. but if you, say, add a key or change a value, you may get a completely different order

20:39 shortlord: amalloy: it still does not work:

20:39 (dosync

20:39 (alter fields map #(assoc-in % [3 :bandit] false))

20:39 (alter fields assoc-in [field 3 :bandit] true)))

20:39 that's the error: clojure.lang.LazySeq cannot be cast to clojure.lang.Associative (repl-1:582)

20:40 amalloy: shortlord: well, one issue is that you're passing the arguments to map in the wrong order: it will look like (map @fields #(fn...))

20:41 shortlord: amalloy: I tried partial and even a custom fn, but it didn't help

20:41 amalloy: the other is that assoc-ing will only work on maps and vectors; if fields contains lists or seqs, it won't do the right thing

20:43 shortlord: amalloy: that's strange, because I am operating on a vector

20:43 amalloy: shortlord: then it's probably the first problem

20:43 shortlord: amalloy: well, partial is supposed to curry a function, right?

20:44 so I thought this should work: (alter fields (partial map #(assoc-in % [3 :bandit] false)))

20:45 amalloy: it does seems that way

20:47 shortlord: amalloy: do you know a good paste service that supports clojure syntax highlighting? I could paste the whole source then

20:47 amalloy: so fields is a (ref of a) vector of things you want to work with; each things is a vector whose fourth element is a map you want to add :bandit false to?

20:47 shortlord: http://gist.github.com

20:48 &(let [fields (atom [[0 1 2 {:player true}]])] (swap! fields (partial map #(assoc-in % [3 :bandit] false))) @fields)

20:48 sexpbot: ⟹ ([0 1 2 {:bandit false, :player true}])

20:49 shortlord: amalloy: https://gist.github.com/747927

20:51 amalloy: shortlord: map is going to return a seq, not a vector

20:51 &(map inc [1 2])

20:51 sexpbot: ⟹ (2 3)

20:51 amalloy: &(vec (map inc [1 2]))

20:51 sexpbot: ⟹ [2 3]

20:51 clojurebot: map is lazy

20:52 amalloy: so after you map over fields, it's turned into a lazy seq and the next assoc-in fails because it's not a vector

20:52 the easiest fix is to make it back into a vector when you're done: (comp vec (partial map...))

20:53 clojurebot: that was surprisingly on-topic. have a cookie, i guess

20:53 clojurebot: Titim gan éirí ort.

20:54 amalloy: shortlord: follow all that?

20:55 shortlord: amalloy: yeah, that works and makes sense :)

20:55 thx a lot

20:55 this channel is incredibly helpful :)

21:13 tomoj: if aleph clients are channels, you can only issue one request at a time without causing problems about figuring out which response was to which request, right?

21:55 hippiehunter: is there some relative of clojure.contrib.monads.maybe-m that throws an exception or logs on what step it failed?

21:56 brehaut: hippiehunter: why not just use exceptions or conditions?

21:57 hippiehunter: because the only failure condition is nil and i'm not good enough with macros to make that a palatable syntax

21:58 amalloy: hippiehunter: write a monad transformation on top of maybe-m?

22:01 hippiehunter: Im pretty noobish when it comes to doing anything other than basic consumption of monads. I was just asking to see if there was anything already in existance that my search missed.

22:02 brehaut: hippiehunter: while you could do it with a monad or monad transformer i think it would be overkill. great if you want to learn how they work more but probably not the right solution

22:03 hippiehunter: that being said, maybe-m is trivial to write, so you could easily concoct your own version that throws an exception on nil

22:04 tomoj: was there somewhat recently a change in the way the metadata works?

22:04 something to make :static easier, I think?

22:06 did "^:foo" no longer mean "{:tag :foo}"? post 1.2

22:09 amalloy: tomoj: i don't think that's the case, but i'm still on 1.2

22:11 tomoj: oh well, :tag is fine

22:13 shortlord: what is the best way to keep indices in "looping" bounds? for example: if the vector has the length 5, the indices 0 to 4 stay the same, 5 becomes 0, -1 becomes 4, etc. In python it's possible to use the modulo, but clojures (rem -1 5) returns -1 instead of 4

22:14 amalloy: &(mod -1 5)

22:14 sexpbot: ⟹ 4

22:14 shortlord: oh, mod exists as a separate function? great! :D

22:14 amalloy: shortlord: yeah, read the doc for mod and rem. they behave differently for negative numbers

22:15 shortlord: amalloy: ok, thx

22:17 amalloy: btw shortlord, a fun mod trick: ##((juxt quot rem) 23 4)

22:17 sexpbot: ⟹ [5 3]

22:17 cemerick: tomoj: ^:foo means {:foo true} in 1.3

22:17 ^String means {:tag String}

22:17 since 1.2

22:20 bortreb: what's a good way to write and read objects created by clojure with defrecord to and from disk?

22:21 tomoj: cemerick: ah, ok

22:21 cemerick: and then you can do "^:foo ^:bar" for "{:foo true :bar true}" ?

22:21 that would be great

22:21 cemerick: exactly

22:22 tomoj: that will force me to generate a bunch of stub classes if I keep it this way... :(

22:25 joshua__: Question for you guys. I'm trying to help my uncle out by building a dll in C++. I want to talk in the C++ channel to ask questions, but it says that the message can't be sent. What am I missing here or is this a glitch?

22:25 amalloy: joshua__: you probably need to register your nick

22:25 bortreb: do something like /msg nickserv identify <your-password> ?

22:30 anthony__: (completely new at all things lisp/functional) I'm using doseq to iterate through the elements in a vector, and I need to append each one to a string, which will be the value of my function. What's the best way to do this? Should I be using map instead of doseq?

22:31 cemerick: anthony__: welcome :-)

22:31 ,(map #(str "foo" %) (range 10))

22:31 clojurebot: ("foo0" "foo1" "foo2" "foo3" "foo4" "foo5" "foo6" "foo7" "foo8" "foo9")

22:31 amalloy: anthony__: you should be using reduce, probably

22:31 * cemerick jumping to solutions too quickly, per usual

22:31 amalloy: &(reduce str ["foo1" "foo2" "foo3"])

22:31 sexpbot: ⟹ "foo1foo2foo3"

22:32 anthony__: Ah man, that's so elegant.

22:32 amalloy: anthony__: welcome to lisp! :)

22:32 cemerick: of course, apply is far more efficient for string concatenation

22:32 amalloy: well yes

22:32 cemerick: &(apply str ["foo1" "a" "k"])

22:32 sexpbot: ⟹ "foo1ak"

22:33 anthony__: Dang it. I used apply in another function. Tried to use it here and couldn't figure it out. Java has ruined me.

22:33 Thanks for the help.

22:34 amalloy: anthony__: good thing you couldn't figure apply out - now you know about reduce, too!

22:35 anthony__: haha very true

23:03 Lajla: (thunk)

23:03 I take that back.

23:03 (thunk-cps Lajla)

23:03 So, what have you got for me baby

23:04 currentB: eh, if I'm implementing a recursive descent parser, is it only necessary/ideal to put one dosync before the recursion entry to handle everything? is that bad form?

23:06 amalloy: currentB: why do you need mutable state for a parser?

23:06 $google fnparse

23:06 sexpbot: First out of 104 results is: joshua-choi/fnparse - GitHub

23:06 https://github.com/joshua-choi/fnparse

23:08 currentB: yeah i found stuff like that but it's for an undergrad class where we could just use whatever language we want, and I figured it'd be cool to use clojure but it's probably best to just go with the method the rest of the class is supposed to use

23:08 definitely against the current in a few places..

23:09 amalloy: currentB: well, parsers are very recursive in nature; it's very convenient to be able to backtrack and have the right state already on the stack without having to restore it manually from a ref

23:12 currentB: k cool I'll meditate on that a bit :) thanks again

23:54 mister_roboto1: is there a library function to get the index of some value in a collection? e.g. if i have [:a :b :c] i want to pass :b and get 1 back

23:55 if there is something built in, i can't find it

Logging service provided by n01se.net