#clojure log - Apr 28 2011

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

0:18 mec: I used a macro within a deftype and now (use :reload 'ns-with-deftype) is throwing Linkage Error: attempted duplicate class definition

0:25 ah, apparently you cant use types before they're defined ;p

0:26 tomoj: linkage error? never seen that before

0:27 mec: I was referring to a type in a macro before i defined it, I guess it created it for some reason

1:21 technomancy: slamhound just got smarter; works on 92% of our work project's namespaces.

1:22 chrissbx: How do I create a recursive local definition? Like letrec in Scheme.

1:23 amalloy: chrissbx: letfn is letrec

1:24 chrissbx: thanks

1:24 amalloy: if you don't need mutual recursion, just name your anonymous function: ##((fn ! [n] (if (zero? n) 1 (* n (! (dec n))))) 5)

1:24 sexpbot: ⟹ 120

1:26 chrissbx: aha

1:32 Vinzent: why enlive is moving into clojure? it's great lib, but I can't see any reason to include it in clojure itself

1:33 amalloy: citation needed?

1:33 i mean, if you say it it's probably true, but i don't know how i could judge why it's the case without even a link to the evidence that it's happening

1:34 Vinzent: https://github.com/clojure/data.enlive

1:35 it's even have its own name! (why not data.templating then)

1:35 amalloy: i think that indicates that it's moving into the new version of contrib

1:36 eg, https://github.com/clojure/tools.logging is the new version of clojure.contrib.logging

1:36 clojurebot: You don't have to tell me twice.

1:36 Vinzent: yeah, that's what i mean

1:36 amalloy: contrib is *not* synonymous with clojure. to move into core is very different from moving into contrib

1:37 especially now that it's being split up

1:38 Vinzent: but contrib (as i see it, maybe i'm wring) is the place for general things, like logging, data structures, etc, and enlive is specialized lib

1:39 i mean, why not include hiccup, ring and compojure then?

1:40 amalloy: *shrug* that's pretty subjective. contrib has some kind of server-socket library

1:41 dnolen: Vinzent: enlive is useful for many kinds of data transformation, also hiccup, ring, compojure, issues of who submitted patches to those projects.

1:43 seancorfield__: http://dev.clojure.org/display/design/Contrib+Library+Names

1:44 i am a bit surprised that the enlive name was carried over

1:45 markoman: what is the difference between hiccup and enlive?

1:45 dnolen: seancorfield: ah nice, ring *is* getting folded in.

1:45 amalloy: i'm glad to hear ring is getting in. it's very nice

1:45 seancorfield__: the current list of active repos can be seen here https://github.com/clojure

1:45 chrissbx: Is there a "println" that doesn't add a space between each argument?

1:45 markoman: im using hiccup on my project, would it be easy to change it to enlive?

1:46 amalloy: &(prn 1 2)

1:46 sexpbot: ⟹ 1 2 nil

1:46 amalloy: &(print 1 2)

1:46 sexpbot: ⟹ 1 2nil

1:46 seancorfield__: ,(println (str "list" "of" "strings"))

1:46 amalloy: hrm

1:46 clojurebot: listofstrings

1:46 chrissbx: yeah, str.

1:46 amalloy: i mean, for sure you can use str

1:46 Vinzent: dnolen, ok, i've just been interested in selection criteria for contrib

1:47 chrissbx: yep, true; thanks for ppointing it out

1:47 seancorfield__: i haven't used ring... probably will get to it at some point... especially now it'll be org.clojure/net.ring :)

1:48 Vinzent: a lot of it depends on having someone willing to actively maintain the "new contrib" library - someone with a signed CA on record

1:48 ambrosebs: hi

1:48 seancorfield__: i pushed for c.c.sql to be promoted because i rely heavily on it at work

1:50 ambrosebs: I'm trying to bind dynamic variables with deftest

1:50 (def a 2)

1:50 (binding [a 1]

1:50 (deftest we

1:50 (println a)))

1:50 this prints 2

1:50 how do i print 1?

1:50 amalloy: they're called dynamic because they're not lexical

1:51 if you wanted lexical bindings, you could just use (let...)

1:54 Vinzent: markoman, enlive follows different (from hiccup and similar templating engines) philosophy, so i think it can require some effort to move from hiccup

1:56 ambrosebs: the context: I have a macro `with-stevedore-impl` that sets up some bindings, and I want to place deftests inside it

1:57 markoman: well need to see library itself

1:57 ambrosebs: it doesn't look like it's possible.. but i don't quite understand why

1:58 chrissbx: Is there a way to trace all function calls (print function name and arguments, and maybe return value) in some scope?

1:58 Vinzent: ambrosebs, i think this binds a only at def time, but you need bindings when fn will be called, so place it inside deftest

1:58 ambrosebs, or around the call of the test

1:59 ambrosebs: Vinzent: looks like that's the way to go, thanks!

1:59 markoman: then i have a question. if I store string to datastore and I'd like to evaluate it on clojure, how it is done and what security issues I should handle?

1:59 for example: (:k (eval "{:k 1}"))

2:00 where "{:k 1}" i stored as a string to data store

2:04 Vinzent: chrissbx, there are clojure.contrib.trace, that might help

2:05 markoman, you can use read, but i believe there should be the other way to store collections in your db

2:06 markoman: the problem is, that "collection" can be things like: "1", "1,2", "{:k 1}", "[1,2,3]", "any string",...

2:07 "1,2" not good example

2:08 Vinzent: &(read-string "1")

2:08 sexpbot: ⟹ 1

2:08 Vinzent: &(read-string "{:a 1}")

2:08 sexpbot: ⟹ {:a 1}

2:09 markoman: i may a problem with types then...

2:09 &(= (type 1) (read-string "1"))

2:09 sexpbot: ⟹ false

2:09 markoman: &(= (type 1) (type (read-string "1")))

2:09 sexpbot: ⟹ true

2:09 markoman: well, maybe not

2:12 but this isnt working: (read-string "(println 2)") ?

2:12 hiredman: markoman: are you kidding?

2:13 markoman: evaluating any string as a clojure code?

2:13 Vinzent: markoman, it's only reads a string and returns clojure datastructure, so you are getting plain list; you can eval it then, if you want

2:14 markoman: ok, that can help with security issues. if they are only datastructures, then there are less possible problems

2:20 Vinzent: btw, is there a form strongly associated with clojure? like, schemers have call-cc and common lispers have defmacro or (loop (print (eval (read)))). What's about clojure?

2:21 What a cool name can i pick for my blog? What must be written on my new t-shirt?

2:22 ambrosebs: xD

2:22 sounds like an awesome idea

2:23 amalloy: (-> (read) (eval) (print) (loop)) is less inside out but not actually legal clojure

2:23 ambrosebs: was just thinking that

2:23 darn

2:27 Vinzent: amalloy, well, repl is an all-lisp thing (so primarily associated with CL), there should be something more clojurish... something about functions, concurrency, what else?

2:27 thorwil: Vinzent: lazy blog name must be forced

2:27 markoman: my eye catches defn, :clojure-keyword and ns clojure.name.space from my codes, but they are not that unique

2:28 ambrosebs: what about dosync?

2:28 Vinzent: thorwil, yes, and laziness :)

2:31 markoman: "Don't know how to create ISeq" is strongly associated with my coding too ;)

2:32 amalloy: haha

3:18 thorwil: Enlive has no function that will simply return the content of a file, no selection, no wrapping!?

3:22 question then is how to read files from the resources dir myself

3:23 ambrosebs: something like slurp?

3:23 ,(doc slurp)

3:24 clojurebot: "([f & opts]); Reads the file named by f using the encoding enc into a string and returns it."

3:25 thorwil: ambrosebs: yeah, problem is slurp doesn't handle the relative path

3:25 ambrosebs: ah

3:26 seems to work for me

3:27 thorwil: actually, i'm wrong by one level. the enlive forms will happily work with a "templates/foo.html", but with slurp it must be "resources/templates/foo.html"

3:27 ambrosebs: ah

3:27 ,(. System getProperty "user.dir")

3:27 clojurebot: java.security.AccessControlException: access denied (java.util.PropertyPermission user.dir read)

3:27 ambrosebs: that should give pwd

3:30 ataggart: if you're not doing anything with the file contents, why are you slurping it into a string?

3:30 you might find stuff in clojure.java.io more useful

3:32 thorwil: ataggart: i need the content as argument for an enlive snippet. initially i thought html-resource would be for that case, but it wraps <html> and <body> around the content

3:33 ataggart: I only went though dnolen's enlive tutorial, but I thought the point of the defsnippet stuff was to have enlive pull the content out of files

3:33 thorwil: i can't find any mention of "resources" as part of the path, or any use of System in the Enlive source, so i still wonder how it knows to just look inside resources

3:34 ataggart: clojure.java.io/resource ?

3:35 have you looked at the tutorial? I think the some of the helper files in there had custom paths for the file locations

3:35 https://github.com/swannodette/enlive-tutorial

3:47 raek: thorwil: it's on the classpath (lein puts it there)

3:49 thorwil: (-> "resources/templates/404.html" slurp en/html-snippet) does what i want. or it has to be ((en/snippet "templates/404.html" [:p] []))

3:50 where :p makes it unnecessarily specific, but if i use :*, the content will appear thrice

3:54 raek: thorwil: I would suggest (-> "templates/404.html" io/resource slurp en/html-snippet)

3:55 this uses the classpath instead of the current working directory

3:55 which will also work when if you make an uberjar of your project

3:57 thorwil: ah, thanks

4:12 i use a single base.html as skeleton for all pages. it references a main.css. it works everywhere, except on /admin/*. here firefox complains about a bad selector and a missing closing } on a line number that doesn't exist in the css file

4:13 * thorwil wonders if a gremlin is at work

4:16 Kerris: it's you

4:16 you are the gremlin

4:23 thorwil: awesome, for /admin mains.css is served like it should, but for /admin/test one of my handlers is triggered instead.

4:26 and i thought static files served from the war dir had priority over any route i write

4:28 maacl_: LauJensen: Are you around?

4:36 thorwil: all the trouble because i didn't have a / in front of main.css

4:38 clgv: thorwil: hopefully you learnt that now for next time ;)

4:47 fortxun: $seen rhickey

4:47 sexpbot: rhickey was last seen quitting 1 week and 1 day ago.

5:50 fliebel: What kind of data do you use seque for? I'd think infinite lazy computationally intensive stuff, but I'd love to hear more cases.

5:51 ilyak: Where do I find help on clojure.lang.Compile command line arguments?

5:55 fliebel: ilyak: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compile.java#L33

5:56 Sp basically, it just takes a bunch of files. I don't see any code for handling other stuff.

6:44 * fliebel doesn't like this weird syntax https://github.com/dcolthorp/matchure

6:47 fliebel: I'd rather have something with a FSM and function composition. Or maybe not. I wonder how this is done: https://github.com/cgrand/regex

6:49 ilyak: ant is pain

6:49 clgv: fliebel: the last one seems nice.

6:49 ilyak: still pain after all years

6:50 fliebel: Yea, as I see it, patter matching is just regex for sequences.

6:52 clgv: cgrande's regex seems to be a different way to create standard regular expressions which could be useful if you have to build these expresion dynamically since you dont need to build a regex string

6:54 fliebel: right

6:56 sid3k: guys, I've decided to give a try to clojure after several months of break but I'm getting the same exact error again

6:56 after I create a new project using lein

6:57 I can't run lein deps without any error. ant produces a long error output

6:58 even though I've recent version of clojure and lein, still it tries to get clojure and install again as I see

6:58 any ideas?

6:59 here is the output: https://gist.github.com/946164

7:00 fliebel: sid3k: 1.2 has been released, so these snapshot builds are out of date.

7:00 I'm not sure if they are even around anymore.

7:00 So just using 1.2.0 should be fine.

7:00 sid3k: yeah, it works that way

7:03 no_mind: I declared a transient map but when I use assoc! to add key it, the key is not added

7:08 clgv: no_mind: you have to use the return value of assoc! to see the changes in general - though in some special cases it might work

7:09 no_mind: k

7:10 fliebel: how does a transient decide the cost of mutating vs copying?

7:14 clgv: fliebel: that's a source code lookup question, I guess ;)

7:17 fliebel: clgv: Okay, there we go… dusting of java knowledge.

7:17 * fliebel has a bookmakr for clojure.lang

7:18 clgv: *g*

7:18 $source transient

7:18 sexpbot: transient is http://is.gd/WJdgXr

7:18 clgv: $source TransientVector

7:18 sexpbot: Source not found.

7:18 fliebel: clgv: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ATransientMap.java

7:19 clgv: $source assoc!

7:19 sexpbot: assoc! is http://is.gd/UU78OT

7:19 clgv: thx

7:20 fliebel: still deeper...

7:20 clgv: hmm no "upper" in fact. doAssoc is abstract ;)

7:21 fliebel: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentVector.java#L385

7:22 clgv: map example: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentHashMap.java#L198

7:23 ah it has to do with the tree structure

7:23 fliebel: I see some stuff with the root node, but I don't really understand it.

7:24 clgv: afair most structures are tree-ish

7:26 humm it's strange: TransientHashMap.doAssoc always returns this

7:26 fliebel: clgv: yes, but this.root is changed or not.

7:27 So I think that if the root of the tree is changed, it behaves like an immutable one, otherwise just a few childs are changed.

7:27 clgv: that doesnt amtter since you should get the identic jvm object back

7:28 fliebel: clgv: But if the .get methods use the root attribute, it'd just work, right?

7:28 clgv: yeah, I think so

7:28 assoc! only calls assoc on each key-val-pair. so no magic happening overthere

7:29 fliebel: I think one needs to understand the tree structure to know what is going on.

7:29 clgv: no, you dont need to. you do get exactly the same TransientHashMap jvam object back.

7:30 fliebel: yes, but *maybe* with a different root node.

7:30 clgv: that doesnt matter since you have to see the change then as well!

7:30 fliebel: huh, yea… true

7:31 clgv: would be interesting now, why it behaves differently

7:31 fliebel: then I don't see how it can return a different map.

7:31 clgv: I don't either

7:32 fliebel: Maybe I'll ask again when the side of the globe with clojure/core on it awakes.

7:32 clgv: yeah. let me know what they answered in case I am not around to read it ;)

7:33 fliebel: sure :)

7:33 clgv: atm it looks like black magic ;)

7:52 mec: what does it mean to have a final variable that is a subclass with non final variables

8:14 fliebel: What is the syntax for these pre and post conditions?

8:16 mec: (fn [x y] {:pre [(pos? x) (neg? y)] :post [(= % 10)]} (+ x y))

8:30 Is it possible to update from a jdk7 snapshot to a newer one without downloading the whole thing?

8:34 fliebel: mec: Thanks.

8:37 jfields: is there a better way to (filter #(= contract-name (:contract-name %)) list-of-maps)

8:38 I do that often enough that it feels like there is an idiom I'm missing.

8:40 Chousuke: well you could make the function point-free but that's not really better. :/

8:41 mec: (filter #{contract-name} (map :contract-name list-of-maps)) ; is better for varying degrees of better

8:42 Chousuke: hmm

8:42 jfields: what does "make the function point-free" mean? sorry I'm not familiar with that phrase.

8:42 Chousuke: (filter (comp #{contract-name} :contract-name) list-of-maps)

8:43 jfields: it means that instead of creating a lambda explicitly, you use function composition and partial application or currying

8:43 jfields: Chousuke, gotcha, thanks.

8:46 Chousuke: unfortunately comp and partial are a bit too clumsy in clojure so point-free style is not as idiomatic as in Haskell for example.

8:46 mec: I gave up on partial, its easier to use #(f a %) than (partial f a)

8:46 Chousuke: in haskell you can do stuff like map (-) . (+1) [1, 2, 3], but in clojure you'd have to do (map (comp - (partial + 1)) [1 2 3])

8:47 mec: Chousuke: . is infix comp?

8:47 Chousuke: IIRC yes

8:47 I haven't actually done any haskell beyond some tutorials :/

8:51 zdennis: Is there a easy way to convert a clojure file to yaml?

8:51 I see the https://github.com/lancepantz/clj-yaml project

8:52 and was curious if there was another way or if that was recommended

8:56 fliebel: &(destructure ['a 1 'b 2 ['c 'd] [1 2]])

8:56 sexpbot: ⟹ [a 1 b 2 vec__36718 [1 2] c (clojure.core/nth vec__36718 0 nil) d (clojure.core/nth vec__36718 1 nil)]

8:57 fliebel: zdennis: Why not json?

9:04 How can I tell in a macro if a form was quoted or not? (= (first s) 'quote) maybe?

9:04 feels weird...

9:06 chouser_: fliebel: that should be about right, though I would be suspicious of the desire to do it.

9:08 fliebel: chouser: Well, yes. I am too. I'm considering ways to do destructuring properly.

9:10 I want to do it with functions rather than a huge macro pile, which works mostly. Now I'm trying to add some icing.

9:11 chouser: to replace the current implementation in clojure.core?

9:11 fliebel: chouser: Huh? whre?

9:11 mec: what are you trying to destructure

9:12 chouser: fliebel: Clojure already does destructuring, so I'm not quite sure what you're trying to do.

9:12 fliebel: chouser: Oh, no, I mean pattern matching actually.

9:13 I found this one, which uses a lot of weird tricks, with the question marks and quoting. https://github.com/dcolthorp/matchure

9:13 chouser: ,(destructure '[[a b c] [4 5 6]])

9:13 clojurebot: [vec__1177 [4 5 6] a (clojure.core/nth vec__1177 0 nil) b (clojure.core/nth vec__1177 1 nil) c (clojure.core/nth vec__1177 2 nil)]

9:13 chouser: fliebel: ah, pattern matching. I see.

9:18 fliebel: chouser: Well, destructure is nice, but does not what I want really. I don't want to bind stuff, just expand it.

9:18 or maybe I do, but.. let me see

9:20 zdennis: I'd like to play around with a clojure library, I've downloaded it, built it with lein, installed it, but trying to require it in the interactive-clj prompt can't find it.

9:20 This is my first attempt to play with clojure, so I'm sure I'm doing something stupid

9:20 or not doing something

9:20 any pointers?

9:21 raek: fliebel: fyi, another pattern matching lib: http://www.brool.com/index.php/pattern-matching-in-clojure

9:21 Chousuke: zdennis: you most likely forgot to include it in the classpath when you started the repl

9:21 zdennis: you should just be able to run "lein repl" from the library's top level directory

9:21 raek: I like it's syntax better than matchure's

9:22 zdennis: Chousuke: thank you, that worked

9:24 raek: zdennis: "lein install" puts the lib in your local maven repo, but that doesn't automatically make it available whenever you launch clojure somewhere

9:24 zdennis: raek: is there a way when using the repl to make maven repository available if you want to play around with different libraries?

9:24 fliebel: raek: This too has a lot of werid stuff going on. It looks a lot more sane though.

9:24 raek: zdennis: if you are a beginner, then you probably want to create a new lein project, add the lib you are interested in as a dependency and then do lein deps and lein repl

9:25 chouser: fliebel: I'm not sure that clojure.core/destructure is of any use to a pattern matching lib.

9:25 raek: clojure does not use the "system wide install" approach which many other languages use

9:26 which libraries to use, and what versions of them, is handled in a per-project basis

9:26 fliebel: chouser: Me neither, but it does handle the & stuff.

9:27 raek: zdennis: you might want to check out cake. it has a "global project", which lets you try a library without creating a project for the "play seesion"

9:28 zdennis: that sounds like what I need ,thx raek

9:31 dnolen: fliebel: pattern matching is a special case of predicate dispatch, always looking for help on my pred match work :)

9:34 fliebel: dnolen: Uhm, okay. Could you explain that?

9:36 dnolen: fliebel: predicate dispatch is a more generalized form of pattern matching - pattern matching w/ guards is not that dissimilar from predicate dispatch, except that predicate dispatch is open - anybody can add another case later.

9:37 in fact the only novelty I'm introducing is that guards can be predicates that are stored in a logic db, the logic db can use that info to reorder clauses to prevent the kinds of problems you run into w/ pattern matching.

9:39 fliebel: dnolen: predicate dispatch is the same thing that cond is doing, tight? only faster and more flexible.

9:40 dnolen: fliebel: if by faster and more flexible you mean - doesn't try clauses in the order you wrote them, and it can be extended :)

9:43 fliebel: dnolen: tbh, I don't see how that helps much with my problem. If I can help with the dispatch without reading a ton of papers, that'd be fun though.

9:46 dnolen: fliebel: you could probably use one of those previously mentioned libs and be just fine. But if you're interested, only two papers - Efficient Predicate Dispatch, Compiling Pattern Matching to Good Decision Trees. Both are short and approachable, I think.

9:47 * fliebel has troubles with priorities ;)

10:10 cemerick: dnolen: congrats on the contrib include :-)

10:27 fliebel: okay, dnolen, where are those papers of yours?

10:39 dnolen: cemerick: thx!

10:40 fliebel: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.47.4553, http://moscova.inria.fr/~maranget/papers/ml05e-maranget.pdf

10:40 fliebel: dnolen: Yea, great to see logos in contrib :) found the papers btw, although your notion of short and understandable seems to be different from mine :)

10:40 dnolen: fliebel: heh ;)

10:41 fliebel: I had some trouble find out where the names started and stopped, and then I got the dylan one and all.

10:41 dnolen: fliebel: the predicate dispatch one is I think pretty easy to understand, it's not important to understand their algorithm tho, just the general idea.

10:41 clgv: fliebel: lol 31 papers is indeed not short for a paper ;)

10:41 s/papers/pages/

10:41 sexpbot: <clgv> fliebel: lol 31 pages is indeed not short for a paper ;)

10:41 dnolen: fliebel: the Maranget paper seems mathematical, it's not really, it's just notation so they don't have to write OCaml

10:42 fliebel: anyway, I'll see if I can read some of it later. I'm going to play with CPS first :)

10:43 dnolen: fliebel: nice

10:53 no_mind: I have a nested map and a sequence which contains the path (hierarchy) of the key for value to fetch. Is there a function which will let me fetch the key from nested map ? Or do I need to iterate over the map ?

10:54 mec: (get-in map [key1 key2])

10:54 also assoc-in, and update-in

10:54 err is that what you're asking

10:57 no_mind: mec: lets say I have a map {"user" {"admin" {"status "1"}}} and a sequence ("user" "admin" "status") . I want to find the value of "status". What is the easiest way to do this ?

10:58 clgv: it's like mec suggested: ##(get-in {"user" {"admin" {"status "1"}}} ["user" "admin" "status"])

10:59 &(get-in {"user" {"admin" {"status" 1}}} ["user" "admin" "status"])

10:59 sexpbot: ⟹ 1

11:01 clgv: and ##(assoc-in {"user" {"admin" {"status" 1}}} ["user" "admin" "status"] 2)

11:01 sexpbot: ⟹ {"user" {"admin" {"status" 2}}}

11:08 dakrone: when you have something like http://pastebin.com/DwCrYqNw how can I get it to resolve correctly and not give me "More than one matching method found: writeNumber"?

11:09 clgv: dakrone: type hints. I guess you need them for "jg" as well

11:09 mec: I believe the args are being passed to instance? backwards

11:10 try #(instance? %2 %1)

11:10 clgv: mec: ah yes. that as well ;)

11:11 mec: err nope, im wrong

11:12 clgv: &(instance? java.lang.Integer (int 0))

11:12 sexpbot: ⟹ true

11:12 dakrone: the condp is correct, this worked on 1.2, on 1.3 it trows, even if I type hint both the obj and jg

11:12 *throws

11:12 clgv: what does it throw?

11:13 dakrone: java.lang.IllegalArgumentException: More than one matching method found: writeNumber

11:13 mec: what arities does writeNumber have?

11:14 dakrone: they're all 1 arity, just different classtypes

11:15 mec: do you have a generic Object one?

11:16 dakrone: no, only ones for Integer, Long, Float, BigDecimal, etc number types

11:17 scottj: cake channel name?

11:20 raek: scottj: #cake.clj

11:21 clgv: thats weird: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Class

11:22 ok it's not lol

11:22 fliebel: clgv: Reversed the arguments?

11:22 clgv: examples for condp should use asymmetric predicates ;)

11:23 mec: clgv: what do you mean

11:23 clgv: mec: I also did think that the argument order should be reversed ^^

11:24 mec: ,(condp instance? 5 Integer 'Integer Long 'Long Float 'Float Double 'Double BigInteger 'BigInteger)

11:24 clojurebot: Integer

11:25 raek: ,(instance? Integer 5)

11:25 clojurebot: true

11:25 raek: the order condp applies the function always surprises me

11:25 but it does fit isa?...

11:26 mec: ,(isa? 5 Integer)

11:26 clojurebot: false

11:28 raek: ,(isa? (class 5) Integer)

11:28 clojurebot: true

11:29 * thorwil wonders if pattern matching / predicate dispatch would be a good fit for url-handler routing

11:43 clgv: I tried to provide one of my deftypes with meta-data like: clojure.lang.IObj (withMeta [this, new-meta-data] ...)

11:43 but I get: java.lang.AbstractMethodError with no description

11:44 mec: did you define (meta [this]) also?

11:45 fliebel: clgv: Typehints maybe?

11:45 clgv: mec: humm no. lol. which interface is it?

11:45 fliebel: clgv: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IObj.java

11:45 mec: IObj

11:46 clgv: ah it's in IMeta. thats why I forgot it

11:48 java.lang.ClassCastException: "MyDeftype cannot be cast to clojure.lang.IPersistentMap" :(

11:49 ah found it

12:13 fliebel: ((match (literal 1) (coll (literal 3) (other #(every? even? %))) _ (literal 3)) [1 [3 4 2] 2 3]) ; true

12:27 clgv: can incanter handle a list of maps as dataset or do I have to build seq for every row?

12:52 ok I converted the data.

12:53 Ramblurr: can anyone please explain why the nullpointerexception is thrown in this example: http://www.ideone.com/COjaV ?

12:54 joegallo: extra parens

12:54 (defn foo [n] (<--- this one right here, delete it

12:55 fliebel: nice one :)

12:55 Ramblurr: joegallo: Ahh! thanks

12:55 joegallo: np

12:56 Ramblurr: joegallo: why did that almost work, but fail at the end? how did the interpreter interpret (hehe) that ?

12:56 joegallo: 1. do the work of printing the numbers, 2. execute the function returned by 1.

12:56 but 1 (doseq ...) returns nil

12:57 so you are (nil)

12:57 invoking nil as a function, hence npe.

12:57 Ramblurr: joegallo: gotcha, thanks again

12:58 joegallo: np, again :)

13:05 fliebel: How does a transient decide whether to mutate or copy? I looked at the source with clgv, be we couldn't figure it out.

13:12 amalloy: fliebel: fwiw, i test for quoting with (= (first s) 'quote)

13:13 needed it for sexpbot so he can macro-expand your form for sneakiness, but still leave quoted sections alone so that code you provide doesn't get mangled

13:13 eg ##(macroexpand '(.getName x))

13:13 sexpbot: ⟹ (. x getName)

13:13 mec: fliebel: what do you mean? doesn't a transient always mutate?

13:14 amalloy: mec: no

13:14 whereas if you asked him to eval (.getName x) he expands that into pages and pages of code to verify that it's an allowed operation

13:16 &(let [x (transient [])] (dotimes [n 100] (conj! x n)) (persistent! x))

13:16 sexpbot: ⟹ [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99]

13:16 amalloy: hm

13:16 mec: would you know an example of where a transient copies instead of mutating?

13:16 amalloy: well, i expected that example to be one

13:16 * fliebel is catching up

13:17 amalloy: the point is that conj! returns to you a new list. that list may be a pointer to the same one you gave it, if it chose to mutate that; or it may give you a new one back if that was more efficient

13:17 if you throw away the result of conj! you're doing it wrong

13:19 fliebel: &*clojure-version*

13:19 sexpbot: ⟹ {:major 1, :minor 2, :incremental 0, :qualifier ""}

13:20 fliebel: &(let [x (transient {})] (dotimes [n 100] (assoc! x n n)) (persistent! x))

13:20 sexpbot: ⟹ {0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7}

13:21 mec: ah i forgot maps swap to more efficient implementations

13:21 fliebel: Would that be it? Just the move from array-map to hash-map?

13:22 &(let [x (transient (hash-map)] (dotimes [n 100] (assoc! x n n)) (persistent! x))

13:22 sexpbot: java.lang.Exception: Unsupported binding form: (dotimes [n 100] (assoc! x n n))

13:22 fliebel: &(let [x (transient (hash-map))] (dotimes [n 100] (assoc! x n n)) (persistent! x))

13:22 sexpbot: ⟹ {0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7}

13:24 fliebel: &(let [x (transient (apply hash-map (range 20)))] (dotimes [n 100] (assoc! x n n)) (sort (persistent! x)))

13:24 sexpbot: ⟹ ([0 0] [1 1] [2 2] [3 3] [4 4] [5 5] [6 6] [7 7] [8 8] [9 9] [10 10] [11 11] [12 12] [13 13] [14 14] [15 15] [16 16] [17 17] [18 18] [19 19] [20 20] [21 21] [22 22] [23 23] [24 24] [25 25] [26 26] [27 27] [28 28] [29 29] [30 30] [31 31] [32 32] [33 33] [34 34] [35 35... http://gist.github.com/946808

13:27 fliebel: There you have it, that seems to work, only the second example is weird.

13:27 If it changed back to an array map it would contain nothing, if it did not, it would contain everything.

13:29 no_mind had some code this morning that did this. I wonder what he had.

13:29 amalloy: fliebel: you have mismatched parens in your second example

13:29 fliebel: amalloy: Third one then...

13:29 amalloy: sexpbot tried to fix them but guessed wrong

13:30 fliebel: I count like a repl.

13:30 no_mind: fliebel: well my code was creating an acyclic directed graph

13:30 amalloy: fliebel: i feel sure there are other situations in which it might give you a different pointer

13:32 fliebel: amalloy: clgv and I traced the code down to the transient, and it looked like it modifies the root attribute, but always returns the same object.

13:48 apgwoz: has anyone heard from Raynes?

13:49 amalloy: apgwoz: his power is out, and cell service is spotty

13:49 apgwoz: (or anyone else from the affected tornado states for that matter?)

13:49 amalloy: cool.

13:49 (well, uncool about power, but cool that he's ok)

13:49 amalloy: yeah

13:50 astoddard: A question with an apparently erroneous answer on stackoverflow piqued my interest. http://stackoverflow.com/questions/5821585/clojure-proxy-and-override

13:50 * fliebel hardly noticed the tornado news, but *phews*

13:51 astoddard: It appears a call to proxy can attempt to implement an non-existing base method: (proxy [Object] [] (nonExistingBaseMethod [] "Foo"))

13:51 Is that nonExistingBaseMethod actually callable in any way?

13:51 fliebel: I'd say so.

13:52 amalloy: &(.getName (proxy [Object] [] (getName[] "test")))

13:52 sexpbot: java.lang.IllegalStateException: Var null/null is unbound.

13:52 amalloy: hm

13:52 that looks like a clojail bug, but it doesn't work in the repl either

13:54 astoddard, fliebel: clojure.contrib.repl-utils/show indicates that a proxy created in that way does not have a method with that name

13:54 fliebel: amalloy: So do you have to define an interface first?

13:55 amalloy: probably

13:55 though in that case you may just want to reify?

13:55 i guess not

13:56 astoddard: amalloy: agreed, no method in the proxy. Interestingly an entry is in the IPersistentMap available from __getClojureFnMappings.

13:59 Ramblurr: I'm using a for to put strings inside a list basically (for [...] (fun-that-returns-a-str)), these strings contain spaces

13:59 and when I call count on the result of the for loop, its interpreting each word as a separate element

14:00 what's the proper way to put a string into a list so the spaces between words are preserved?

14:01 amalloy: huh? you are wrong; ##(count ["this has spaces"])

14:01 sexpbot: ⟹ 1

14:02 Ramblurr: herm

14:03 fliebel: Teh codez for my micro matcher. Comments? https://gist.github.com/946857

14:04 amalloy: &(count (for [x (range 10)] (clojure.string/join " " (repeat x "word"))))

14:04 sexpbot: ⟹ 10

14:39 thorwil: given that (ds/defentity Quark [^:key milch sahne yoghurt]) expands to (clojure.core/defrecord Quark [milch sahne yoghurt] appengine-magic.services.datastore/EntityProtocol ...

14:40 how could i access the vector [milch sahne yoghurt] afterwards?

14:41 mec: (nth (macroexpand-1 '(ds/defentity Quark [^:key milch sahne yoghurt]) 3)

14:43 dnolen: fliebel: nice.

14:43 thorwil: heh

14:44 mec: but without repeating the macro call. i mean, this information has to be accessible from Quark afterwards, somehow

14:45 dnolen: thorwil: reflection is one way.

14:45 fliebel: dnolen: Thanks. What amount of dead tree would you think I can consume during 4 hours of train?

14:46 dnolen: fliebel: probably both papers, I read papers on the way to work, my commute is only 30 min on train, so it usually takes 2 rides to finish one.

14:47 mec: thorwil: you could probably use symbol capture but it really depends what you're doing

14:47 dnolen: of course, I usually have to read a paper 2 or 3 times before I understand it...

14:47 fliebel: dnolen: Okay, good :) I wonder if the empty cartridge will make it to the end of the 31 pages one :P

14:56 sritchie: ,((fn [f a b] (f a b)) (read-string "+") 2 3)

14:56 clojurebot: 3

14:56 sritchie: does anyone know why that doesn't eval to 5?

14:57 justinlilly: ,(= (read-string "+") '+)

14:57 clojurebot: true

14:57 justinlilly: ,((fn [f a b] (f a b)) '+ 2 3)

14:57 clojurebot: 3

14:58 justinlilly: do you have to unquote the + somehow?

14:58 ,('+ 2 3)

14:58 clojurebot: 3

14:58 justinlilly: that's effectively what's happening.

14:59 technomancy: justinlilly: needs resolve or eval

14:59 ,('+ {'+ :plus} :not-found)

14:59 clojurebot: :plus

14:59 sritchie: ,((fn [f a b c] (f a b c)) (read-string "+") 1 5 5)

14:59 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (3) passed to: Symbol

14:59 sritchie: yeah, interesting

15:00 hiredman: justinlilly: I'd suggest learning about lisp readers

15:00 justinlilly: ,((fn [f a b] ((eval f) a b)) (read-string "+") 2 3)

15:00 clojurebot: DENIED

15:00 justinlilly: tsk.

15:00 mec: you're calling a symbol, which take 1 or 2 args

15:00 hiredman: and following that up by learning about evaluators

15:00 followed up by writing a lisp

15:00 justinlilly: hiredman: direct comments to sritchie :)

15:00 manutter: ,((fn [f a b] ((resolve f) a b)) (read-string "+") 2 3)

15:00 mec: the first arg is the environment to look themselves up, and the 2nd is not-found

15:00 clojurebot: 5

15:00 sritchie: ah, that's really interesting

15:00 hiredman: mec: map

15:01 not environment

15:01 sritchie: ,('+ {'+ 4} 2)

15:01 clojurebot: 4

15:02 mec: ,(('+ {'+ +}) 2 3)

15:02 clojurebot: 5

15:02 mec: ,(('+ {} -) 2 3)

15:02 clojurebot: -1

15:17 TimMc: Wait, what does invoke on a Symbol do?

15:17 fliebel: TimMc: Lookup in a map

15:17 TimMc: ah, like keywords

15:17 fliebel: oh, maybe not, that was my python mind confusing me

15:17 TimMc: ,('foo {'foo :sym, :foo :key})

15:17 clojurebot: :sym

15:18 TimMc: ,('bar {'foo :sym, :foo :key} :qux)

15:18 clojurebot: :qux

15:18 TimMc: with optional default

15:18 fliebel: oh, okay

15:18 * TimMc reads scrollback more carefullly

15:19 TimMc: mec: And by "environment" you mean an associative data structure?

15:21 mec: TimMc: indeed

15:22 on invoke symbol calls RT.get(arg1, this, not-found)

16:09 ordnungswidrig: hi all

16:42 Can protocols extend protocols?

16:50 mec: ordnungswidrig: I dont think so

16:54 edw: Do the modular contrib projects work in 1.2.1?

17:02 ohpauleez: edw: I don't think so. I think they're only for 1.3

17:02 But I haven't personally tried

17:02 some (most?) will probably work

17:02 since most of the code of contrib isn't 1.3 specific

17:03 edw: OK. "Should I be using a 1.3 prerelease?" is a question I'm thinking of asking.

17:05 ohpauleez: If you're just playing around, I'd say go for it!

17:05 if you're doing production work, I think you should stick to 1.2.1

17:07 edw: I'm doing active development, so dealing with occasional changes isn't a biggie. I'd rather do that than deal with migrating to the new libs later.

17:07 ohpauleez: Yeah, sure. I've been working on 1.3 stuff. There's a lein plugin for working with multiple clojure version, I believe it's called lein-multi

17:08 edw: Doesn't it just come down to futzing with your project.clj?

17:10 technomancy: lein-multi is designed for testing libraries for cross-compatibility, though nothing prevents you from using it to test applications as well.

17:11 edw: https://github.com/technomancy/swank-clojure/blob/master/project.clj#L7

17:12 edw: Ah. I'm writing apps. (A Scheme -> JS translation web service right now.)

17:13 ohpauleez: edw: You're quite the polyglot programmer, huh? :)

17:14 ordnungswidrig: I try to solve the expression problem on event handling: events (data) and handlers (behaviour)

17:15 I made the handlers protocol (with a single method) and deftyped the events that extend protocols

17:15 https://gist.github.com/947353

17:15 any idea on this? I don't like the runtime registration of the handler protocols

17:16 edw: ohpauleez: I just hate writing CPS-style programs in JS (too much syntax) so I figured I'd write something that would compile Scheme to JS a la CoffeeScript so I can get on with my life.

17:17 ohpauleez: edw: For sure, I definitely understand. I think it's a cool project.

17:19 edw: Actually, I'm writing it because I'm sort of depressed, and I need something fun to do. I think I'm having a Bipolar Lisp Programmer kind of day.

17:19 apgwoz: edw: have you looked at cpscm? or did you just want to write it yourself?

17:19 edw: apgwoz: See above. ;)

17:19 apgwoz: yeah. we wrote at the same time :)

17:20 edw: But I'll check that out. Maybe it's a pile of mud I can help make a little bigger.

17:20 apgwoz: never as fun as writing it yourself though...

17:20 i'd vote for that

17:20 :)

17:21 dnolen: edw: have you seen scheme2js ?

17:22 edw: dnolen: No. What's it written in?

17:22 dnolen: edw: it's insane actively worked on, http://www-sop.inria.fr/indes/scheme2js/

17:22 supports call/cc

17:23 pretty much all of r5rs is there.

17:23 the main issue is that documentation is sparse.

17:24 edw: inria.fr... Is that home to OCaml?

17:24 dnolen: edw: yup.

17:25 edw: Ah.

17:25 dnolen: compiler does trampolining transformation, so tail recursive code is guaranteed to not stack overflow.

17:25 was considering playing around with it and Node.js

17:26 edw: Maybe I should just cut out and go to Oscar's (local dive). Reintroducing myself to primitive java character i/o is causing my body to sigh.

17:26 ohpauleez: I think fogus has a functional JS/Node.js project going on. I don't know how far he's gotten with it though

17:26 technomancy: that seems a bit backwards; why put yourself on an untested runtime with no libraries when there are lots of really solid scheme compilers already?

17:26 ohpauleez: but it'd be worth looking at

17:29 edw: technomancy: Because I'm done hosting my own projects. I ran my consulting firm's web site on a framework I wrote in Scheme (Magic) and I sometimes had to connect to SLIME at 3am to re-start the mofo. The Joyent Node Service is nice. But I hear you. I miss Scheme48.

17:30 * edw joins #scheme to see if any Schemes currently suport SLIME...

17:32 dnolen: edw: have you used Geiser?

17:32 edw: No.

17:32 * edw googles.

17:32 dnolen: edw: works beautifully with Racket

17:33 edw: And by Racket, do you mean what MzScheme's become?

17:34 dnolen: edw: yes

17:34 edw: I just read the front page slash manifesto. Sounds like one of my people. I was bitching about having to bounce the JVM just to update a project's dependencies.

17:34 ...just the other day.

17:35 Oh noes, he supports Guile...

17:37 hiredman: you can add classes and what not, it just can run into odd scoping issues and can be tricky to deal with

17:37 edw: dnolen: Downloading Racket...

17:37 hiredman: so there is nothing preventing people from rolling their own runtime classloading whatever, clojure just doesn't provide something out of the box

17:38 ordnungswidrig: How can I extract all functions out of a protocol?

17:38 edw: hiredman: Right good point. [As edw sticks head in oven.]

17:41 no_mind: In a nested map how do I insert a new key at a any given level. Foreg. I have {"user" {"admin" {"status" "1"}}} and I want {"user" {"admin" {"status" "1", "roles" "2"}}}

17:41 hiredman: https://github.com/hiredman/clojurebot/blob/master/src/clojurebot/plugin.clj

17:42 ordnungswidrig: no_mind: ,(update-in {"user" {"admin" {"status" "1"}}} ["user" "admin"] assoc "roles" 2)

17:42 (update-in {"user" {"admin" {"status" "1"}}} ["user" "admin"] assoc "roles" 2)

17:42 ,(update-in {"user" {"admin" {"status" "1"}}} ["user" "admin"] assoc "roles" 2)

17:42 clojurebot: java.lang.Exception: Unable to resolve symbol:   in this context

17:42 ordnungswidrig: *grr*

17:42 no_mind: alternatively, which data structure is most suitable for presenting hierarchical data

17:44 dnolen: ,(assoc-in {} [:foo :bar :baz] 1)

17:44 clojurebot: {:foo {:bar {:baz 1}}}

17:44 ordnungswidrig: no_mind: thats ok, however I'd user keywords: {:users {:admin {:status 1 :roles 2}}}

17:44 dnolen: no_mind: ^

17:44 no_mind: assoc-in wont add a key but will replace

17:45 dnolen: no_mind: update-in

17:47 lancepantz: edw/hiredman: that's what classlojure is for

17:47 we use it in cake to update dependencies without bouncing the jvm

17:47 hiredman: ~cake

17:47 clojurebot: cake is http://wondermark.com/030/

17:47 lancepantz: it has multiple application classloaders, you can use it to run multiple versions of clojure in the same jvm too

17:53 ordnungswidrig: can one determine if a value is a protocol? The type of a protocol seems to be PersistentArrayMap

17:53 I'm on 1.2

17:53 dnolen: sick, http://www.artisancoder.com/2011/04/cps-and-beta-reduction/

17:58 ordnungswidrig: dnolen: nice

17:59 ataggart: protocols are not types, but you can check if an object satisfies a protocol with (satisfies? P obj)

18:02 ordnungswidrig: ataggart: I know. But I have (defprotocol Foo) (defprotocol Bar) and I wan't to register a protocol (-type) at runtime, say (defn add-handler [p] (alter handlers conj p)) But I want to make sure that p in the latter function is a protocol

18:02 not something else

18:03 ataggart: protocols are not types

18:03 ohpauleez: ordnungswidrig: I'd look at the supers of the a protocol, and see what interface you can check for

18:03 ordnungswidrig: ataggart: I know.

18:04 ohpauleez: the runtime representation of a protocol is a map, not a java type

18:04 ohpauleez: ah right

18:05 but does it include any extra interfaces, outside of a standard map?

18:05 ataggart: the question is tantamount to asking if an argument is a multimethod.

18:07 ohpauleez: ordnungswidrig: There are a keys you can check for

18:07 ordnungswidrig: other question: is using protocols for dispatch faster than using multimethods?

18:07 Ramblurr: is there a function like (do ..) that evalutes all the exprs *and returns* all the results?

18:07 ordnungswidrig: ohpauleez: the keys, yes

18:07 ohpauleez: ordnungswidrig: yes

18:08 technomancy: Ramblurr: pvalues

18:08 amalloy: vector

18:08 &(vector 1 2 3)

18:08 sexpbot: ⟹ [1 2 3]

18:08 technomancy: oh yeah, that's better

18:08 or list

18:08 Ramblurr: yea i thought of that, but I don't want a list, because the returned values are already going into a list :\

18:09 amalloy: Ramblurr: clojure does not have multiple-value return

18:09 look at mapcat

18:09 ordnungswidrig: Ramblurr: what about with-meta

18:09 Ramblurr: inside a (for..) i want to evalute several exprs and have for return all the results

18:09 amalloy: &(mapcat #(if (even? %) [:even %] %) (range 10))

18:09 sexpbot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer

18:10 amalloy: &(mapcat #(if (even? %) [:even %] [%]) (range 10))

18:10 sexpbot: ⟹ (:even 0 1 :even 2 3 :even 4 5 :even 6 7 :even 8 9)

18:10 Ramblurr: ah interesting

18:14 hiredman: ,(for [x (range 10) :when (even? x) y [:even x]] y)

18:14 clojurebot: (:even 0 :even 2 :even 4 :even 6 :even 8)

18:15 hiredman: it's a shame that for doesn't have an explicit concat option

18:17 amalloy: i agree

18:17 i feel dirty having to use mapcat

18:18 hiredman: that's a pretty neat trick

18:19 Ramblurr: amalloy: i'm not sure how to apply mapcat to this example: http://www.ideone.com/Y4Sn9

18:19 you can see the (do.. ) where I'd like it to return both

18:20 dont pay attention to the redundancy of (foo.. ) ;)

18:21 amalloy: Ramblurr: like hiredman says, you can't do it with for

18:22 this is...almost exactly identical to the mapcat example i gave

18:22 Ramblurr: amalloy: yup, but where would you add the call to (foo ..) in the mapcat example

18:22 amalloy: (mapcat #(if (even? %) [(foo %) "even"] ["odd"]) (range 50))

18:22 Ramblurr: oh :\

18:29 mec: this sounds like a job for (fort [a (range 5) b (range 5) :transform (partial apply concat)] [a b])

18:33 ataggart: xy?

18:33 clojurebot: xy is http://mywiki.wooledge.org/XyProblem

18:34 amalloy: speaking of xy, Ramblurr, did you figure out what was going on with your "strings with spaces" issue?

18:35 mec: that's just silly. you can (apply concat) the result of the for; but that doesn't resolve the "issue" of wanting to return two things sometimes and one thing other times: you still have to wrap everything in a vector

18:36 mec: if none of those are collections themselves you could always flatten

18:37 its too bad concat doesnt work as flatten-1

18:38 amalloy: ugh. flatten is good, but the language would be better without putting it in core so that people stop trying to abuse it for one-level flattening

18:39 nickik: http://stackoverflow.com/questions/5232350/clojure-semi-flattening-a-nested-sequence/5232787#5232787

19:46 devn: how can I passing something like a namespace as an arg without 'quoting it?

19:46 s/passing/pass

19:46 sexpbot: <devn> how can I pass something like a namespace as an arg without 'quoting it?

19:46 devn: (myfn foo.core) => (myfn 'foo.core)

19:49 scgilardi: the arguments to a function are evaluated before the function is invoked. if you need exactly what you're saying, myfn needs to be a macro.

19:50 devn: scgilardi: *nod*

19:50 i figured as much, no big deal

19:50 thanks though

19:57 hiredman: foo.core is a symbol, 'fore.core is a quoted symbol, there is no literal syntax for namespaces

20:08 choffstein: anyone here use clj-cont?

20:22 dnolen: choffstein: clj-cont is now delimc

20:23 choffstein: ah, thanks.

20:23 not available on clojars yet?

20:23 Ah ... for 1.3.0

20:24 dnolen: choffstein: lemme double check fi that's necessary

20:27 choffstein: done, 0.1.0 pushed to Clojars, compat with 1.2.0

20:27 choffstein: You're a lovely, beautiful person

20:27 And I kiss you

20:27 dnolen: choffstein: not much documentation, but it basically works like shift/reset in Scheme.

20:27 choffstein: relatively easy to sort out what's going no by looking at the test.

20:29 choffstein: I'll take a peek. Thanks.

20:30 I'm trying to build a very simple component based web framework just to learn clojure

20:30 and it seems like I can do it by passing around function objects and using refs and transactions ... but continuations seem sexier if I can figure em out

20:31 dnolen: choffstein: cool, that's why I originally developed delimc 2 1/2 years ago, to port weblocks. delimc is too slow for general use, but definitely more than fast enough for I/O bound things.

20:31 choffstein: i'm 99% sure i'm too stupid to get it working, but what doesn't kill me only makes me ... smarter?

20:33 carllerche: I'm trying to write a connection pool, would it be better to represent it as an atom -> { "hostname" PersistentQueue } or maybe ref -> { "hostname" ref -> PersistentQueue } and then use dosync?

20:33 dnolen: choffstein: yeah it was never completely clear to me how to implement it properly, but I never looked at weblocks or Seaside deeply enough. arc would be good to look at as well.

20:33 carllerche: or maybe a ref -> { "hostname PersistentQueue } directly and still use dosync?

20:34 choffstein: dnolen: yeah, I was playing around with seaside and was wondering if I could implement something really simple in clojure that captured the essence of the idea

20:35 dnolen: choffstein: it's definitely possible. just have to map unique keys to a frozen computation. and garbage collect those frozen computations somehow.

20:37 choffstein: dnolen: the reset/shift system is new to me, so I'm still trying to figure out how the freeze the computation. I come from a ruby background, so trying to understand the parallel is rocking the boat for me

20:38 dnolen: reset, mean start recording everything here and allow me to jump back at any time - shift.

20:38 s/mean/means

20:38 sexpbot: <dnolen> reset, means start recording everything here and allow me to jump back at any time - shift.

20:40 choffstein: hmmm, interesting

20:40 and reset won't actually execute the code?

20:41 dnolen: continuations are the new hotness at ICFP 2011, they're doing a whole workshop on them.

20:41 choffstein: I'm just really trying to figure out how to implement call-backs via continuations.

20:41 I don't think I understand them well enough at the moment.

20:41 hiredman: "new"

20:42 choffstein: hiredman: isn't that how the world works?

20:42 dnolen: well the academics are excited about them - a lot of type theory to sort out.

20:46 choffstein: i'm not gonna lie, dnolen, the test cases don't help me at all :D

20:52 dnolen: choffstein: I would do something simple like try to solve the arc challenge.

20:52 choffstein: okay

20:54 carllerche: Is there a functional difference between ref-set and alter besides just convenience?

20:54 dnolen: choffstein: use ring for the server, handlers are just fns, so you can just use reset around the body of the fn. that would be pretty awesome to see actually.

20:56 carllerche: you'd have to read the ref to change it with ref-set, I believe. (ref-set ref (inc @myref)) vs. (alter ref inc)

20:57 carllerche: dnolen: yeah... i'm just wondering if there are any functional differences under the hood

20:57 or if one could implement ref-set in terms of alter (or vice versa)

20:57 TimMc: carllerche: Doesn't look like it. https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Ref.java#L172

20:58 carllerche: hmm... indeed, thanks :)

20:58 hiredman: ~alter

20:58 clojurebot: alter is always correct

20:58 TimMc: carllerche: Also, there doesn't appear to be any difference in the stated semantics, so that *probably* won't change out from under you.

20:59 hiredman: Because it is easier to reason about?

20:59 dnolen: TimMc: if you look at the code ref-set and alter are quite different. alter is more "atomic"

20:59 hiredman: TimMc: that is an out of context quote of rich talking about alter vs. commute

21:00 carllerche: but, the transaction would restart if ref-set isn't atomic

21:01 hiredman: unless you really need the stm I would use an LBQ or similar instead of refs or atoms

21:02 dnolen: TimMc: but maybe not, my understanding of concurrency issues is still noob-level.

21:09 choffstein: dnolen: Hmm, don't think I really understand what you mean there by just wrapping the fns with reset. Where does that get me?

21:10 I'm trying to basically implement a component system where call-backs are implemented using continuations

21:10 dnolen: choffstein: you create holes that you can callback into at any point.

21:11 choffstein: on the delimc landing page you can see I'm saving points I can return while allow the function to run to completion as well.

21:13 choffstein: dnolen: Right. I think what I am trying to do is do that will the components. I am basically having each component be a set of state and procedures that renders itself with call-backs that affect the state. My thought was to use continuations to implement those call-backs for when a link is pressed or a form is submitted.

21:14 dnolen: choffstein: you can render a page, see that something is missing, store the continuation, call another function, produce a page with an input field, when the user submits that you can then call the stored continuation to finish the *original* page.

21:14 choffstein: ah, interesting

21:15 brehaut: dnolen: whats the link for this lib?

21:16 dnolen: brehaut: https://github.com/swannodette/delimc

21:16 brehaut: thanks!

21:16 dnolen: choffstein: that's the essence of the arc challenge which is why I recommended doing that.

21:17 choffstein: http://www.paulgraham.com/arcchallenge.html

21:17 choffstein: i'll take a read

21:18 hmm, interesting challenge. i'll give it a try :)

21:19 dnolen: choffstein: if you do it you should definitely do a blog post about, I've been hoping somebody would give it a shot with delimc.

21:19 choffstein: yeah, well, I just started using clojure a month ago and it is my first lisp, so don't hold your breath ;)

21:19 dnolen: choffstein: the cool thing is very complex form flows become trivial.

21:20 brehaut: dnolen, choffstein: it also seems useful for irc bots

21:20 dnolen: brehaut: true, never considered that.

21:22 choffstein: okay, I think I am getting this reset / shift stuff...

21:23 Though, only in its simplest form...

21:33 dnolen: how would funcall-3 and funcall-4 change if it had been (+ 2 (shift ...)) instead of (+ (shift ...) 2)? Does it matter?

21:34 from reading up on scheme's reset / shift, it seems like anything between reset / shift is put into a lambda and applied where 'k' is in the shift statement

21:38 dnolen: choffstein: in that case it wouldn't matter no.

21:43 choffstein: okay, didn't think so.

21:54 Ramblurr: amalloy: regarding the strings as spaces, that was just me being confused by the toString version of the sequence

21:54 amalloy: I had miscounted, the (count) result was correct

21:55 its weird seeing a list printed like (This is a sentence broken into chunks, but you would never know it)

21:56 when I had expected something like ("This is a sentence" "broken into chunks" ", but you would never know it")

21:56 amalloy: Ramblurr: instead of str, you can use pr-str, which prints in a way that preserves type information

21:57 &((juxt str pr-str) '("string" "more"))

21:57 sexpbot: ⟹ ["(\"string\" \"more\")" "(\"string\" \"more\")"]

21:58 amalloy: &((juxt str pr-str identity) '("string" "more"))

21:58 sexpbot: ⟹ ["(\"string\" \"more\")" "(\"string\" \"more\")" ("string" "more")]

21:58 amalloy: okay whatever

21:58 i'm not sure what you did to get that confusing output

21:59 choffstein: dnolen: I'm feeling like the examples of reset/shift I am seeing are just unnecessarily complex versions of let / fn... obviously, I must be missing something here.

22:01 dnolen: choffstein: let / fn doesn't let you continue from any point.

22:01 amalloy: choffstein: the chapter on continuations in On Lisp blew my mind. have you read it?

22:01 choffstein: amalloy: not yet. i'll try to read it

22:02 amalloy: i didn't really internalize it all

22:04 dnolen: choffstein: bascially shift let's you create a hole, this hole is a function. You can call this function to reinsert a new value and continue where that hole was made.

22:04 Ramblurr: amalloy: im having trouble applying the mapcat idiom to my actual function http://pastebin.com/dVQGJ7XG

22:04 all of a sudden i'm getting the "wrong number of args" exception :\

22:04 dnolen: choffstein: this is achievable if you write all your code in CPS style by hand - but delimc does that for you, it walks you code and applies that transformation automatically.

22:05 choffstein: dnolen: Ah, I see. I think I am just confusing myself with how I thought I would use callbacks with the code I was playing around with and how continuations really work.

22:07 dnolen: choffstein: it's pretty heady stuff, I still don't really understand it thoroughly myself.

22:08 choffstein: yeah. trying to figure out new concepts is like going around a drain. You just keep circling and circling until finally it clicks

22:14 amalloy: Ramblurr: the i in your original version has disappeared in the mapcat version

22:14 clojure is complaining that you created an #(anonymous function) that takes 0 args (it has no % in it), and you're calling it with one arg

22:15 Ramblurr: oh! so that error is referring to the anonymous function, not the call to parsen

22:16 amalloy: yes. user$parsen$fn means "an anonymous function, nested inside of parsen, which is in the namespace user"

22:17 since you're not *using* i at all, i'd rewrite this as something like (apply concat (repeatedly n #(do whatever, return a vector)))

22:17 no point getting map(cat) involved if you don't use the input sequence for anything

22:17 &(repeatedly 10 (rand-int 5))

22:17 sexpbot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

22:17 amalloy: &(repeatedly 10 #(rand-int 5))

22:18 sexpbot: ⟹ (2 3 0 2 4 0 2 0 3 0)

22:19 dnolen: choffstein: https://github.com/swannodette/delimc, perhaps example that don't involve arithmetic make it clearer

22:20 choffstein: dnolen: yeah, i'm trying to work through them now in my head. thanks.

22:20 dnolen: choffstein: I added an example w/ strings

22:25 daaku: i'm running into an issue where macro expansion is happening before the associated use statement runs, making the symbol references inside the macro be invalid (i think). code/output here: https://gist.github.com/754b1f7e4c5a65e1e58e ("app" is a macro).. anyone know how to get around this?

22:25 Ramblurr: amalloy: so i can put multiple function calls inside a [] and they'll all be evaluated for the return?

22:26 tomoj: is that moustache's app or is it under your control?

22:26 daaku: tomoj: moustache's app

22:27 tomoj: (appengine-environment-type) won't change, will it?

22:27 I mean, in one jvm

22:27 daaku: tomoj: nope, it wont

22:27 tomoj: then decide at compile time which to do

22:28 one solution, I think, would be (if (= :interactive (appengine-environment-type)) (defn wrap-dev [handler] ..) (def wrap-dev identity))

22:28 daaku: i see, switch to def and let the if run

22:28 tomoj: but a bit ugly

22:28 right, or that

22:28 probably less ugly

22:28 daaku: lets try

22:32 tomoj: probably better to have the use call outside the handler

22:33 daaku: tomoj: not sure i follow (very much a n00b)

22:33 i tried this: https://gist.github.com/754b1f7e4c5a65e1e58e -- but still fails. seems like i'm misunderstanding how macro expansions work

22:35 tomoj: hmm.. right

22:36 why not just always add those uses to the namespace?

22:36 maybe a tiny bit of startup overhead, but that's it, right?

22:37 daaku: i guess to keep ring-devel and it's deps in :dev-dependencies i guess :).. but not terribly important i guess

22:37 tomoj: ah

22:37 daaku: but i want to understand why it still won't work anyways ;)

22:37 amalloy: daaku: (do a b c) compiles a b and c at the same time, so wrap-reload won't be linked in yet while you're compiling

22:38 daaku: amalloy: ah! that explains it

22:38 amalloy: there's a special exception if (do) is a form at the very top level, in which case it compiles/runs, compiles/runs, etc

22:38 tomoj: whoa

22:39 so eval could save you, but, :'(

22:39 amalloy: tomoj: or a macro

22:39 tomoj: how?

22:39 clojurebot: with style and grace

22:39 amalloy: but really you probably shouldn't be making changes to the compilation environment at runtime

22:40 tomoj: the problem seems the opposite to me

22:40 choffstein: dnolen: can you have a continuation you don't pass anything to?

22:40 tomoj: we want to check at compile-time whether to make runtime changes, no?

22:40 oh, I see

22:40 "compilation environment" including which namespaces are used

22:41 amalloy: indeed

22:41 tomoj: you take the use call in the latest gist to be at runtime?

22:41 dnolen: choffstein: that seems reasonable/possible to me.

22:42 daaku: what is the best way to solve the problem of optional dependencies then?

22:42 amalloy: tomoj: (appengine-environment-type) is a runtime function

22:42 maybe. i dunno

22:42 daaku: depend on things anyway

22:42 it costs so little

22:42 tomoj: depends..

22:43 ring-devel is probably small

22:43 seems java deps can get quite costly in e.g. uberjar time

22:43 ..and uberjar result size

22:44 amalloy: if you're actually shipping two (or N) different versions of the jar, then fine

22:44 tomoj: daaku: btw, I think #(identity) can never be called without error

22:44 amalloy: tomoj: wrong

22:45 &((#(identity)) 10)

22:45 sexpbot: java.lang.IllegalArgumentException: Wrong number of args (0) passed to: core$identity

22:45 amalloy: oh

22:45 okay right

22:45 haha

22:45 daaku: haha

22:45 tomoj: I had to try it out a few different ways before realizing..

22:45 amalloy: i was thinking of (constantly identity), sorry

22:45 daaku: nice

22:45 tomoj: yeah, that's what I expected when I tried it I think

22:46 daaku: to be clear #(identity) is (fn [] (identity))

22:47 daaku: tomoj: yep, i didn't realize arity was enforced :)

22:48 which makes sense since defn seems to support arity based dispatch

22:52 tomoj: but only to the defined arities

23:05 choffstein: ...is there a reason why calling count on a dered reference to a list would return a list?!

23:07 whoops, stupid mistake

23:07 miiigghhhtt be time to stop coding

23:46 dnolen: you still here?

23:47 dnolen: choffstein: what's up?

23:47 choffstein: dnolen: I'm pulling my hair out trying to create a continuation using shift / reset that doesn't take any args. any ideas?

23:49 i'm looking at the rules for reset and shift at racket-lang.org, which I assume are similar to scheme's and therefore what you implemented. it's not looking very possible by design...

23:49 see: http://docs.racket-lang.org/reference/cont.html#(form._((lib._racket/control..rkt)._reset))

23:49 dnolen: choffstein: perhaps you can jump back to let expression and return a value you don't use?

23:50 choffstein: but yes, it's not exactly goto.

23:50 choffstein: dnolen: hmm, maybe.

23:50 dnolen: choffstein: but I would argue, do you really need to do that?

23:51 choffstein: dnolen: well, for what I am trying to do, I do...

23:51 dnolen: Which probably means I am going about doing this wrong :D

23:51 dnolen: choffstein: why would you want to return to a place without inserting the missing value?

23:52 choffstein: dnolen: hold on, i'll show you on github in 10 seconds

23:54 okay, didn't quite get what I was looking for :( but here is the code anyway... https://github.com/newfoundresearch/surf

23:55 the code is horrible, but I am just trying to use the continuations in the construct-callback function to delay potentially expensive callback calls. This way, I can put up 20 callbacks, and only actually execute the one that needs to be executed.

23:56 The relevant lines are ~67. The program works as expected, but it doesn't seem to be delaying the callback calls ... just the redirect...

23:57 Oh, shit, I got it

23:57 Just had to move some lines around :D

23:57 dnolen: choffstein: cool.

23:58 choffstein: This is one of those times where I look at my code and say, "okay, it's working ... but there is no way it should be"

23:58 dnolen: choffstein: heh, yeah I would take a moment to sort that out :) Not sure why you need dosync in this code.

23:59 choffstein: because existing-callbacks is a ref that I am altering...

23:59 dnolen: choffstein: why does it need to be a ref?

23:59 choffstein: because if you go down to the 'render' implementation in the counter-component, using a ref prevents me from having to pass around new pages every time a add a call-back

Logging service provided by n01se.net