#clojure log - Jun 12 2011

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

1:09 grantm: Say I want to do (new java.awt.Color my-list) where my-list is (255 0 0), so that I get (new java.awt.Color 255 0 0) in the end. The web says generally the right way is to use apply, but I can't seem to get it to work here (it gives a strange error). How do I do what I want?

1:10 tomoj: first, (java.awt.Color. 255 0 0) is more idiomatic (just some syntax sugar for what you wrote)

1:10 &(apply #(java.awt.Color. %1 %2 %3) [255 0 0])

1:10 sexpbot: ⟹ #<Color java.awt.Color[r=255,g=0,b=0]>

1:11 tomoj: ugly, but works

1:11 you can't apply 'new' or constructors since they're not actually functions, but you can create a function that just calls the constructor and apply it

1:13 &(letfn [(color [[r g b]] (java.awt.Color. r g b))] (color [255 0 0]))

1:13 sexpbot: ⟹ #<Color java.awt.Color[r=255,g=0,b=0]>

1:13 tomoj: something like that could work too

1:17 grantm: thanks a lot! but all these ways seem to hardcode the number of arguments. is there a general way to not do that? (i guess you could build a macro for it?)

2:42 Scriptor`: hi everyone

11:56 mudge: hello

11:56 what is an "associative collection" ?

11:57 what does it mean if a data type is associative?

12:03 anybody here today?

12:07 hey halfprogrammer

12:07 hey, how do I found out if a value is a sequence or not?

12:07 halfprogrammer: Hi

12:08 (seq? BLAH)

12:09 mudge: when you say seq, among collections (list, vecotrs, map and set) (seq? X) returns true only for list

12:09 ,(seq? [1])

12:09 clojurebot: false

12:10 halfprogrammer: mudge: If you are interested in getting true for the rest of the collection types too then use coll?

12:10 ,(coll? [])

12:10 clojurebot: true

12:11 mudge: thanks halfprogrammer

12:11 TimMc: mudge: Associative means there are key-value pairs.

12:12 mudge: TimMc: oh, okay, thanks

12:12 that explains it

12:12 TimMc: Maps (dicts in other languages) are the classic example.

12:12 mudge: TimMc so vectors are also associative then, because vectors have numeric indexes

12:12 TimMc: You might be able to call vectors associative (treating indices as keys) but that might be a stretch.

12:13 mudge: yea!

12:13 TimMc: I think not, though -- maps are primarily accessed by key, not by ordering.

12:13 What's the context?

12:13 mudge: TimMc even sets could be considered associative because in a set the key of a value is the value

12:13 TimMc: That's more of a hack, really. :-P

12:14 mudge: yea

12:14 i am reading somewhere that says that all collections can be treated as sequences

12:14 so I am wondering why all collections are not sequences if they can be treated as sequences

12:15 so a map can be treated as a sequence?

12:15 TimMc: mudge: Sure!

12:15 mudge: wow, neat

12:16 TimMc: ,(map identity {:a 5, :b 6})

12:16 clojurebot: ([:a 5] [:b 6])

12:16 TimMc: ,(type (first {:a 5, :b 6}))

12:16 clojurebot: clojure.lang.MapEntry

12:16 halfprogrammer: mudge: as TimMc said don't rely on ordering of sets and maps

12:16 mudge: then why are all collections not sequences?

12:16 halfprogrammer: ,(sequential? {})

12:16 clojurebot: false

12:16 TimMc: mudge: It's the other way around -- sequences are collections

12:17 ,(coll? (seq '(1 2 3 4)))

12:17 clojurebot: true

12:17 mudge: TimMc, yes I see that

12:17 but if all sequence functions can work on maps then why aren't maps sequences?

12:17 __name__: ,(map #(* % 2) {1 2 3 4})

12:17 clojurebot: java.lang.ClassCastException: clojure.lang.MapEntry cannot be cast to java.lang.Number

12:18 __name__: ,(map #(%) {1 2 3 4})

12:18 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (0) passed to: MapEntry

12:18 mudge: like duck typing, if it walks like a duck and quacks like a duck then it is a duck ----- so why aren't maps sequences if they sequence like a sequence?

12:18 __name__: ,(map (fn [x] x) {1 2 3 4})

12:18 clojurebot: ([1 2] [3 4])

12:19 halfprogrammer: I think we use the term sequence if there is a well defined order of iteration

12:19 that is why vectors and lists are sequential

12:19 i mean (sequential? vec-or-lst) returns true

12:19 __name__: ,(map (juxt first #(* 2 (second %)) {1 2 3 4})

12:19 clojurebot: EOF while reading

12:19 __name__: ,(map (juxt first #(* 2 (second %)) {1 2 3 4}))

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

12:20 __name__: ,(map (juxt first #(* 2 (second %))) {1 2 3 4})

12:20 clojurebot: ([1 4] [3 8])

12:20 mudge: (seq '[4 5])

12:20 ,(seq '[3 4])

12:20 clojurebot: (3 4)

12:20 mudge: ,(seq? '[3 4])

12:20 clojurebot: false

12:21 mudge: halfprogrammer: a vector is not a sequence

12:21 __name__: What's it with quoting the vector?

12:21 halfprogrammer: ,(sequential? [3 4])

12:21 clojurebot: true

12:21 __name__: That does not really make sense.

12:21 ,(seq [3 4])

12:21 clojurebot: (3 4)

12:21 mudge: halfprogrammer, try using seq?

12:21 halfprogrammer: seq? returns true for lazy sequences, I think

12:22 thorwil: hmm, using (defmulti valid-item-range #(nil? %)) things work as expected, but would be more readable in inversion. (defmulti valid-item-range #(not (nil? %))) and flipping true/false on the methods does not work here 0.o

12:26 TimMc: mudge: but a vector is Seqable

12:27 That is, it supports taking (seq) of it.

12:27 mudge: Okay, but why is a map not a sequence if all the sequence functions work on it?

12:28 TimMc: mudge: (first) calls (seq) on its argument.

12:28 mudge: TimMc --- I seeeeee, so a map doesn't support the sequence functions until seq is called on it

12:29 TimMc: ,(type (seq {}))

12:29 clojurebot: nil

12:29 TimMc: ,(type (seq {:a "not empty"}))

12:29 clojurebot: clojure.lang.PersistentArrayMap$Seq

12:29 __name__: ,(seq {:a :foo})

12:29 clojurebot: ([:a :foo])

12:29 TimMc: ,(type {:a "not empty"})

12:29 clojurebot: clojure.lang.PersistentArrayMap

12:29 TimMc: You get back a lightweight iterator over the map, basically.

12:30 mudge: TimMc: i see, thanks

12:30 TimMc: Now that I tihnk about it, that's one of the things that tripped me up at the beginning too.

12:31 mudge: NOw reread http://clojure.org/sequences -- it will probably make more sense.

12:31 mudge: TimMc: okay, thanks

12:32 TimMc: I have to read the clojure.org pages more than once to really internalize the ideas, and it helps to bang my head against some code in the meantime. :-P

12:33 mudge: TimMc: yea

12:33 TimMc: do you have clojure stuff on github? i'm curious

12:33 TimMc: yep, though I can't vouch for the idiomatic-ness of it :-)

12:33 halfprogrammer: :P

12:34 TimMc: https://github.com/timmc/CS4300-hw6 <- a ray tracer I made for a computer graphics class

12:34 __name__: neat

12:34 clojure raytracer

12:34 TimMc: See the README for a link to a better one. :-P

12:34 mudge: cool

12:35 TimMc: I did all my CompGraph assignments in Clojure that semester.

12:35 __name__: It shows how Clojure still scares me :)

12:36 TimMc: Ooh, a github bug!

12:36 I have a file with a ? in its name.

12:36 __name__: github is bugged

12:36 Milestones are garbage.

12:38 TimMc: Try going to either of the first two files in this directory: https://github.com/timmc/CS4300-hw6/tree/master/dev

12:38 I sent them a bug report.

12:38 __name__: Haha

12:39 TimMc: mudge: Oh, and you may wonder how ##(seq "foo") works, given that j.l.String doesn't implement Seqable... I suspect protocols are involved.

12:39 sexpbot: ⟹ (\f \o \o)

12:40 TimMc: Either that or special-casing.

12:42 mudge: TimMc: since String doesn't implement Seq, it looks like Seq turns the string into a list of characters

12:42 TimMc: Yeah, I'm just wondering how it recognizes it.

12:42 hmmm...

12:43 ,(sequential? "foo")

12:43 clojurebot: false

12:43 mudge: TimMc: maybe it recognizes it by checking to see if it is a String type

12:43 TimMc: OK, so there's ISeq, Iterable...

12:44 and I still don't know the difference between seq? and sequential?...

12:46 mudge: TimMc: me either

12:50 __name__: ,iterable?

12:50 clojurebot: java.lang.Exception: Unable to resolve symbol: iterable? in this context

12:51 mrBliss`: seq? is true when the argument is a sequence (generated by a seq call on something non empty). sequential? is true when calling seq on the argument would result in something for which seq? is true (unless it's empty).

12:52 mudge: mrBliss, thanks, where did you find that out?

12:53 tomoj: &((juxt sequential? (comp seq? seq)) {1 2})

12:53 sexpbot: ⟹ [false true]

12:54 TimMc: mrBliss`: Not for strings.

12:54 mrBliss`: mudge: read the source

12:54 TimMc: ,(seq? (seq "foo"))

12:54 clojurebot: true

12:54 TimMc: ,(sequential? "foo")

12:54 clojurebot: false

12:55 mrBliss`: TimMc: Yeah, it's not actually 100% correct, but in general (for [], {}, #{}...) it is ;-)

12:55 tomoj: not maps, see above

12:55 TimMc: well, yeah...

12:55 tomoj: &((juxt sequential? (comp seq? seq)) #{1 2})

12:55 sexpbot: ⟹ [false true]

12:55 tomoj: not sets either

12:56 mudge: &(+ 4 5)

12:56 sexpbot: ⟹ 9

12:56 halfprogrammer: interesting, I am looking at gvec.clj in clojure source file and apparently there is method for sequential. "clojure.lang.Sequential ;marker, no methods"

12:56 mrBliss`: tomoj: Ok, nvm :-)

12:57 tomoj: sequential does not mean seqable

12:57 mrBliss`: https://gist.github.com/950144/51f669b6b62c386330e63071e8870853b0607acf

12:57 tomoj: didn't someone make a nice chart?

12:59 halfprogrammer: mrBliss`: nice

12:59 thorwil: why does what i thought would be a simple boolean flip not lead to equivalent results: http://paste.pocoo.org/show/405093/ ?

12:59 TimMc: Who is swannodette again?

12:59 grantm: noob question: if i do (defmacro my-apply (func args) (cons func args)), it works if i do like (my-apply + (1 2)) but fails if i do (define x (list 1 2)) (my-apply + x) because it doesn't know how to make a seq from a symbol. how do i let it know?

12:59 mrBliss`: TimMc: dnolen

13:00 TimMc: thanks

13:01 tomoj: grantm: is that clojure?

13:01 grantm: yup

13:01 tomoj: params need to be in vectors, there is no define

13:01 grantm: oh, i meant (def x (list 1 2))

13:01 TimMc: I don't think that's the issue.

13:01 tomoj: (defmacro my-apply (func args) ...) certainly shouldn't work at all

13:01 TimMc: grantm: Run (macroexpand-1 `(my-apply + x))

13:02 then look at the cons

13:02 grantm: ah my mistake, i was doing the params list with [], i just copied it wrong

13:02 tomoj: ah

13:03 grantm: i get "don't know how to create ISeq from symbol"

13:03 mudge: why does the reverse function return a list?

13:03 TimMc: grantm: Ah, my bad.

13:03 mudge: &(reverse [3 4 5 6])

13:03 sexpbot: ⟹ (6 5 4 3)

13:03 TimMc: Right, put a println in your macro.

13:03 mudge: &(type (reverse [3 4 5 6]))

13:03 sexpbot: ⟹ clojure.lang.PersistentList

13:04 thorwil: mudge: maybe it's related to performance characteristics?

13:04 mudge: why does it return a list and not a vector because a vector was supplied as the argument

13:04 TimMc: grantm: Your macro is getting arguments ['+ 'x], not ['+ '(1 2)]

13:04 grantm: right

13:05 TimMc: So I think you want to use ~ to evaluate the second argument into a list.

13:09 Hmm, that's not quite right either.

13:09 grantm: TimMc: So the only way I can use ~ is if i'm returning something quoted (right?) I get as far as (defmacro my-apply [func args] `(~func ~@args)), but then when i run it i get the same error.

13:09 halfprogrammer: reverse code: (reduce conj () coll)

13:09 TimMc: grantm: I think apply might actually be a special thing.

13:09 halfprogrammer: Not sure why it is implemented this way...

13:10 grantm: TimMc: Oh, that would be a shame...

13:12 TimMc: grantm: Macros are syntax transformers, and apply actually works with values.

13:13 grantm: TimMc: How can I tell the difference in the future?

13:15 TimMc: I think it's really a rare example.

13:15 manutter: The thing about macros is that they operate on the raw code *before* it actually executes

13:16 TimMc: Look at it this way... (my-apply + x) wants to take `+ and `x and turn it into (`+ `1 `2) ... but `x->(list 1 2) doesn't exist yet.

13:16 manutter: so if you say (defmacro foo [x] (bar ~x)), and then you call (foo y), the value for ~x evaluates to the *symbol* y, not the value of y

13:17 grantm: okay, i think that makes sense, thanks!

13:17 manutter: Macro expansion turns (foo y) into (bar y), and then the bar function actually looks to see what the current value of y is

13:17 the macro-expander never checks the value of y

13:19 TimMc: grantm: The macro expander doesn't even "know" that x is an available var...

13:20 that's the job of the implicit syntax-quote that happens when you call a macro.

13:20 ,`x

13:20 clojurebot: sandbox/x

13:22 tomoj: implicit syntax-quote?

13:25 TimMc: tomoj: Well, when you call a macro, it gets fully resolved names.

13:26 It's getting the syntax from the reader, so you can think of it like syntax-quote having been applied to the expression.

13:27 tomoj: is that new in 1.3.0 or something? or maybe I'm just not understanding what you mean

13:27 is this not a counterexample: (defmacro foo [x] (namespace x)) (foo +)

13:27 TimMc: hrm

13:27 maybe I am wrong!

13:28 Blah, I guess I was confusing it with something else.

13:28 I should not give advice in here when I have not written Clojure in the past month. >_<

14:12 mDuff: My expectation is that (identical? [:a] [:a]) would be true -- given as a clojure object is immutable, I would expect identical values to share identity -- but this isn't the case. What's the basis of my misunderstanding here?

14:13 pdk: it's probably producing a new vector object for each one

14:14 mDuff: What should I be using instead? I'm trying to find a common way to compare native collections in the API doc and coming up empty.

14:14 dnolen: mDuff: =

14:14 mDuff: ahh; I tried ==, and it complained to me about being numeric-only

14:14 dnolen: ,(= [:a] [:a])

14:14 clojurebot: true

14:15 mDuff: thanks!

14:17 TimMc: mDuff: identical? is pointer comparison

14:17 dnolen: what's the best way to check if a class exists? Trying to work around the fact that 1.3.0 has ArityException and 1.2.0 does not.

14:18 TimMc: ,(identical? 3 3)

14:18 clojurebot: true

14:18 TimMc: ,(identical? 300 300)

14:18 clojurebot: false

14:19 TimMc: dnolen: Reflection?

14:19 :-/

14:21 If you don't mind try/catch, there's Class/forName

14:22 ,(Class/forName "ArityException")

14:22 clojurebot: java.lang.ClassNotFoundException: ArityException

14:23 dnolen: TimMc: yeah I saw that

14:23 TimMc: ,(Class/forName "String")

14:23 clojurebot: java.lang.ClassNotFoundException: String

14:23 TimMc: ,(Class/forName "java.lang.String")

14:24 clojurebot: java.lang.String

14:28 dnolen: works well enough for me.

14:34 TimMc: Make it a wrapper function I suppose?

14:34 Also, why do you need to reflect on this?

14:43 dnolen: TimMc: because ArityException doesn't exist in 1.2.0

14:43 TimMc: I'm creating a macro to define the appropriate code depending on whether ArityException exists or not.

14:44 fliebel: How would you explain the different attitude towards exceptions in Python and Clojure?

14:44 dnolen: fliebel: in Clojure exceptions are ... exceptional.

14:45 fliebel: btw, the desire to make fact not be a macro has created a monstrous amount of macros :)

14:45 fliebel: dnolen: how so?

14:45 dnolen: fliebel: implementing IFn

14:48 fliebel: dnolen: rhickey just nuked this idea, but maybe you could generate a map and pass it to extend.

14:49 dnolen: fliebel: No I don't want any overhead.

14:50 fliebel: dnolen: Do you know if the exception thing is technical or just convention?

14:50 dnolen: fliebel: I remember being surprised at exception-for-flow-control in Python since I hadn't really seen that elsewhere.

14:50 fliebel: ( http://jaynes.colorado.edu/PythonIdioms.html#eafp )

14:51 dnolen: I don't really like it.

14:51 TimMc: fliebel: a.k.a. the optimistic approach

14:56 fliebel: TimMc: What do you mean?

14:56 TimMc: fliebel: Assume there won't be an exception, but handle it if there is one.

14:57 fliebel: It seems to be their primary type system.

14:58 TimMc: What does it have to do with their type system>

14:58 fliebel: TimMc: Duck typing, They don't check if something is something, but just try to act as if it where something.

15:00 TimMc: Ah, yeah. That is kind of similar.

15:13 dnolen: 400 lines of AFn.java in 48 lines of Clojure, https://gist.github.com/1021886

15:15 actually more like 33 when you take out all the core.logic crap

15:18 nickik: dnolen, There is a question on stackoverflow about typesystems in Clojure. I am about to anwer it (you could have one in lisp but clojure doesn't is the short version) but i remember reading that core.logic does have something like that. Is that ture? (I have not looked at core.logic jet)

15:19 dnolen: nickik: you could build something like that with core.logic yes, but I haven't done any work along those lines.

15:36 mudge: Clojure has a single primitive construct "loop"

15:36 but what is a construct? how is it different than a form?

15:38 dnolen: mudge: it's one of the special forms, http://clojure.org/special_forms

15:38 nickik: mudge, there are just some things that the compiler has to know

15:39 TimMc: mudge: https://github.com/clojure/clojure/blob/1.2.x/src/jvm/clojure/lang/Compiler.java#L37

15:40 nickik: all the special forms are engouth to build the hole language. So if you want to reimplement the hole langauge you would have to build a compiler that just implements all the spezial forms (and a reader).

15:40 TimMc: whole, even

15:41 mudge: but what is the difference between a special form and a construct?

15:41 fliebel: How many special forms does Clojure have? Scheme has 7, right?

15:42 mudge: Clojure also has exactly one primitive control flow construct:loop

15:42 nickik: i think its soemthing like 12

15:43 fliebel: Hm, maybe if we drop Java interop, we can beat Scheme ;)

15:45 Scriptor: do the .net and javascript (if it exists) versions use the same operators reserved for java interop?

15:48 tomoj: special-form-anchor references 16 special forms: #{'. 'def 'do 'fn 'if 'let 'loop 'monitor-enter 'monitor-exit 'new 'quote 'recur 'set! 'throw 'try 'var}

15:50 TimMc: mudge: "if" and "do" are also control flow constructs, as are "try" and "catch".

15:51 fliebel: There's also the question of how many Clojure *needs*, vs. how many the compiler special-cases.

15:51 mudge: then what is the difference between a form and a construct?

15:51 TimMc: Some of the special-cased forms could be implemented (less efficiently?) as macros.

15:51 mudge: I'm not familiar with the term "construct".

15:54 nickik: a form is basiclly everything right?

15:54 TimMc: yeah

15:54 Scriptor`: that's how I think of it

15:56 TimMc: A form is what the reader reads when you ask it to read one form. :-P

16:00 leeda: I have [sandbar "0.3.0"] in my :dependencies and I ran "lein deps", but when I try to do (:use sandbar.core) I get the following error: https://gist.github.com/b6d2e03a93eac874d048

16:01 It looks like hiccup and sandbar are incompatible? I'm not even using hiccup in this namespace though.

16:06 raek: leeda: looks like this is a bug in sandbar that has been fixed in the snapshot version... https://github.com/brentonashworth/sandbar/commit/4c48185af93b5a86f5c5c38b8e2bcc8a8a676bc0

16:06 leeda: raek: Oh, cool. Thanks!

16:06 raek: that's why you shouldn't use 'use' without :only, folk!

16:06 leeda: yup

16:07 TimMc: "only use :use with :only"

16:17 kephale: hrm, so if one needs an entire namespace the proper thing to do is :require with :as?

16:17 clojurebot: namespaces are (more or less, Chouser) java packages. they look like foo.bar; and corresponde to a directory foo/ containg a file bar.clj in your classpath. the namespace declaration in bar.clj would like like (ns foo.bar). Do not try to use single segment namespaces. a single segment namespace is a namespace without a period in it

16:25 tomoj: TimMc: seems like the question of how many special forms we need is complicated by java interop

16:26 I mean, does it count if you can implement the rest of the special forms in terms of the basis you pick, or do you have to finish c-in-c?

16:34 Tcepsa: #join #emacs

16:34 Whoops, sorry >_<

16:36 TimMc: kephale: Yeah, that seems to work pretty well. clojure.string (or whatever) :as s, etc.

16:37 tomoj: Yeah, I'm excluding Java interop, I don't know how it is even implemented.

16:37 mudge: anybody know where the documentation is for ->>

16:37 ?

16:38 nickik: ,(doc <<-)

16:38 clojurebot: Cool story bro.

16:38 nickik: ,(doc ->>)

16:38 clojurebot: "([x form] [x form & more]); Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc."

16:38 mudge: nickik: I don't understand that documentation, is there further explanation on the web?

16:39 i don't know what " Threads the expr through the forms." means

16:40 nickik: its just puts the first argument you give it to the last position of the secend argument

16:41 mudge: nickik: can you give an example?

16:41 nickik: ,(macroexpand-1 '(->> "test" (count))

16:41 clojurebot: EOF while reading

16:41 nickik: ,(macroexpand-1 '(->> "test" (count)))

16:41 clojurebot: (count "test")

16:42 Scriptor: mudge: check out clojuredocs.org

16:42 nickik: ,(macroexpand-1 '(->> "test" (count) (+ 5) (- 4))))

16:42 clojurebot: (clojure.core/->> (clojure.core/->> "test" (count)) (+ 5) (- 4))

16:42 Tcepsa: mudge: And then takes the result of _that_ and uses it as the last argument of the following function call, if there's another one, etc.

16:42 leeda: how would you write a function to turn all the keys of a map into keywords (if they are strings)?

16:44 mudge: i get it

16:44 nickik: (apply map (map (fn [[k v]] [(keyword k) v]) mymap))

16:44 something like that

16:45 mudge: okay, what's the difference between -> and ->> ?

16:45 nickik: mudge, -> puts it to the second position, ->> to the last

16:45 Tcepsa: nickik: should the first "map" in that be "hash-map"?

16:45 nickik: yes

16:46 leeda: nickik: oh, thanks

16:46 mudge: nickik: thanks

16:46 Scriptor: ,(doc hash-map)

16:46 clojurebot: "([] [& keyvals]); keyval => key val Returns a new hash map with supplied mappings."

16:47 Scriptor: hmm, why not call it map-hash?

16:48 nickik: (apply hash-map (mapcat (fn [[k v]] [(keyword k) v]) {"a" 1 "b" 2 "c" 3}))

16:49 ,(apply hash-map (mapcat (fn [[k v]] [(keyword k) v]) {"a" 1 "b" 2 "c" 3}))

16:49 clojurebot: {:a 1, :c 3, :b 2}

16:49 nickik: now it works

16:50 tomoj: TimMc: well.. I meant more the java implementation than interop. e.g. "apply" isn't implemented using clojure's special forms, so is that cheating?

16:54 hiredman: ,(let [m {:a 1}] (zipmap (keys m) (map inc (vals m))))

16:54 clojurebot: {:a 2}

16:55 hiredman: ,(let [m {:a 1}] (zipmap (map name (keys m)) (vals m)))

16:55 clojurebot: {"a" 1}

17:00 mudge: is it just me or is facebook really slow?

17:05 nickik: its build on php what did you think would happen?

17:14 Scriptor: tbh, php that's compiled to C++

18:33 void_: meh, what should I do about cyclic load dependency?

18:33 Raynes: Redesign.

18:33 void_: that's the only way?

18:33 Raynes: Yep.

18:41 raek: void_: in my expedience so far with Clojure, dependencies between namespaces with purely functional code tends to be cycle-free (or "layered") naturally

18:41 this is quite different from java, where classes often have to have cyclic dependencies

18:42 void_: I just didn't expect that having cyclic dependencies would break everything

18:42 Just used to C.

18:42 Anyway, I fixed it by redesigning.

18:53 mudge: (GET "/browse/*" request (let [[ns var] (str/split (get-in request [:params "*"]) #"/")]

18:53 (html

18:53 (layout

18:53 (namespace-browser (namespace-names))

18:53 (var-browser ns (var-names ns))

18:53 (var-detail ns var)))))

18:53 what is "request" in this: (GET "/browse/*" request (let [[ns var] (str/split (get-in request [:params "*"]) #"/")]

18:53 (html

18:53 (layout

18:53 (namespace-browser (namespace-names))

18:53 (var-browser ns (var-names ns))

18:53 (var-detail ns var)))))

18:53 ?

18:53 where does request come from?

18:54 raek: mudge: gist.github.com next time :)

18:54 mudge: from whatever calls your handler with a request

18:55 í.e. probably jetty

18:55 mudge: raek, okay, i will

18:59 what is this: #"/"

18:59 what is the # syntax?

19:00 raek: mudge: regex literal

19:01 mudge: reak, so #"/" is a regular expression that just means / then?

19:01 raek: yes

19:09 dnolen: IBM's Watson used Prolog ... need to implement DCG's for core.logic

19:10 nickik: dnolen, what how?

19:10 i mean for what?

19:12 dnolen: parsing

19:13 nickik: I think it was kind of cheating that watson got the "questions" as text.

19:14 kephale: nickik: it depends what you think they were advertising…

19:14 the turing test has no speech recognition requirement

19:16 nickik: kephale, yeah but I thought the idea of watson was that it could play just like a human, with the same conditions.

19:17 kephale: well, yeah they didn't achieve that requirement for sure. even though they made that cute point that it had a buzzer presser

19:17 but, if you want to hassle them, a human has to carry its own energy store : P

19:17 and presumably fit on the stage

19:18 nickik: hehe

19:18 kephale: oh the imagery that comes to mind… : P

19:18 nickik: i gues that will take some more time.

19:19 give moors law a couple moore (hehe) years.

19:19 kephale: lol

19:21 nickik: I want to be able to ask my phone questions.

19:21 looking stuff up on wikipedia is to much work.

19:26 TimMc: nickik: I think they also imposed a slight delay on Watson.

19:28 gigamonkey: When did they submit the text? When Trebek started reading the question or when he finished?

19:29 TimMc: dunno

19:42 mudge: I am looking for a request function takes a URL string and returns a map of response data.

19:43 anybody know what namespace the request function is in?

19:45 brehaut: mudge: clj-http

19:45 probably clj-http.core ?

20:09 quotemstr: What's the least ugly way of incorporating some imperative code in the middle of a -> sequence?

20:09 brehaut: write a named function?

20:10 quotemstr: Context is here: http://paste.lisp.org/display/122594 It's not Clojure, but it is Clojure's thrush operator.

20:10 brehaut: -> isnt thrush; its a form rewriting macro

20:11 thrush is a function composition macro

20:11 quotemstr: http://blog.fogus.me/2010/09/28/thrush-in-clojure-redux/

20:11 chouser: thrush is a function composition function

20:11 brehaut: whoops yes

20:11 chouser: :-)

20:12 quotemstr: Sure. I'm just wondering whether there's a more idiomatic way of embedding those assertions.

20:12 brehaut: thanks chouser :)

20:12 quotemstr: Ah.

20:12 brehaut: monads are a _less_ idiomatic way of production compositonal imperative code ;)

20:14 s/production/??/

20:14 sexpbot: <brehaut> monads are a _less_ idiomatic way of ?? compositonal imperative code ;)

20:14 brehaut: producing perhaps is what i meant

20:15 quotemstr: -?> might do what you want. its in contrib somewhere

20:16 -?>

20:16 ,-?>

20:16 clojurebot: java.lang.Exception: Unable to resolve symbol: -?> in this context

20:16 brehaut: clojure.contrib.core

20:16 http://clojuredocs.org/clojure_contrib/clojure.contrib.core/-_q%3E

20:20 [mattb]: anyone here used clojure on android yet?

20:29 quotemstr: I guess what I _really_ want is do-notation.

20:29 [mattb]: AIUI, Dalvik doesn't run Clojure code well.

20:33 [mattb]: ah

20:33 I'm seeing lots of slow startup and memory hogging on google but it seems like that should be remediable

20:37 quotemstr: I wonder why nobody's added more elements of do-notation to ->.

20:38 Scriptor: quotemstr: which elements is it missing?

20:38 quotemstr: Scriptor: Conditionals would be nice. I suppose it's not really a monad, so trying to shoehorn that idea into it might lead to unexpected surprise.

20:42 Scriptor: ,(-> 3 (= 3) (if "hi" "hello"))

20:42 clojurebot: "hi"

20:43 Scriptor: ,(-> 3 (= 4) (if "hi" "hello"))

20:43 clojurebot: "hello"

20:43 Scriptor: quotemstr: what's wrong with using conditionals like above?

20:43 quotemstr: Scriptor: (if (something-p ...) ...)

20:44 Scriptor: Also, your example destroys the "3" value, unless I'm missing something.

20:44 Scriptor: that it does, unless you def it somewhere I guess

20:44 it's like using a stack language but with only one thing ever in the stack

20:45 quotemstr: Right: so you have to manage a stack yourself.

20:46 Scriptor: And it's not trivial to shoehorn normal functions into that model. Without using an embedded lambda like my jezt-passthrough above, it's not clear how one could print "hi 3" instead of "hi".

20:47 Of course, it's also possible that my sense for functional programming has been forever ruined by exposure to LOOP. :-)

20:49 Another idea is to create something like a half ->: instead of threading the last value into the next form's first argument position, it would just provide an anaphoric variable instead.

20:49 Scriptor: quotemstr: hmm, would it also be necessary to be able to print something like "hi 3 true" (given that the conditional returned true)

20:50 what's an anaphoric variable?

20:51 quotemstr: Scriptor: A variable introduced to refer to some value previously computed, but not explicitly bound.

20:51 Scriptor: ah, got it, like %1 and the like?

20:51 quotemstr: The canonical example is AIF: (aif (* a b) (1+ it) 0)

20:51 Yeah, I think you can look at them that way.

20:53 TimMc: ,(if-let [a (+ 3 4)] (* a a) "no")

20:53 clojurebot: 49

20:53 TimMc: eh, that was already bound I guess

20:53 tomoj: quotemstr: I think rich didn't like that idea

20:53 Scriptor: one idea I'm playing with is something like that, but use it to refer to a stack and make a pseudo-stack-lang

20:53 quotemstr: tomoj: Which one?

20:53 tomoj: anaphora in a more powerful ->

20:54 quotemstr: I mean, I can get tolerable syntax with -> using ugly macros, but Haskell's solution looks cleaner to me.

20:54 tomoj: Ah, too bad.

20:54 tomoj: What about explicit bindings?

20:54 TimMc: I think people have written some explicit threading macros that give you something like (--> 5 (* 3 % %) (+ % 1) (println %))

20:54 quotemstr: (-> 4 (+ 2) (<- first (+ 2)) (= 2) ... (+ first))

20:55 TimMc: Any pointers?

20:55 TimMc: Sorry, no.

20:55 tomoj: quotemstr: what would explicit bindings look like?

20:55 TimMc's example is what I was thinking of, rich didn't like the semantics of % there I think

20:55 Scriptor: something like the <- example from above, tomoj

20:56 tomoj: oh, I didn't notice that second arrow

20:56 TimMc: tomoj: The problem being that % should really refer to the first thing only?

20:56 tomoj: at least that it should only refer to one thing, iirc

20:56 TimMc: ah, OK

20:57 I'd like to see his reasoning on that.

20:57 He's usually right, in my opinion, but sometimes it isn't clear until I've heard him talk about it fo 15 minutes in a presentation. :-P

20:59 Scriptor: or at a bar!

20:59 quotemstr: Heh.

20:59 tomoj: can't seem to find the discussion

21:00 hardly anyone calls it "thrush" and searching for "thread[ing]" isn't exactly useful

21:01 Scriptor: was it on irc? Any place to look at them publicly?

21:01 (look at the irc logs)

21:02 tomoj: http://groups.google.com/group/clojure/msg/1eb5cf8fa3248049

21:03 http://clojure-log.n01se.net/

21:04 that above the logs is rich on an arrow extension

21:04 * quotemstr reads.

21:04 tomoj: the rest of the discussion is pretty entertaining I think, crazy dude

21:04 I notice he says "And anything like let-> that allowed you to name the arg has the same problem. There is no good name, as the semantics of the parameter often change with each invocation." but don't really understand what he means

21:05 oh

21:05 that's not your <- suggestion, he just means letting you name the % in TimMc's -->

21:06 Scriptor: looks like the proposer is saying that the wildcard variable changes depending on the last form evaluated?

21:06 quotemstr: Indeed. My suggestion would make names consistent at least.

21:07 tomoj: I do enjoy overusing the arrows and get a bit frustrated when there's one small piece that doesn't work..

21:08 TimMc: I think one take-away from that thread is that -> and ->> are already convenience macros, and that generalizing them is going one step too far.

21:08 i.e., if you need complexity, name it

21:09 Scriptor: right, otherwise you're getting kind of close to making an actual stack language

21:09 TimMc: I guess the places where I have really wanted it *are* in Java interop, though -- I need to call a whole damn chain of FactoryFactoryIterators or whatever to get the instance I want.

21:10 Scriptor: doesn't .. chain its arguments?

21:10 (sorry, clojure newb here)

21:17 TimMc: meh, you get the idea

21:17 "stitchpoints", they're called

21:19 tomoj: I have never seen those

21:19 Scriptor: apparently Rich hates them too

21:19 quotemstr: TimMc: Also ungoogleable.

21:20 Nearly. Found the logs.

21:22 TimMc: I wonder where I saw it then.

21:22 I wonder if Rich is worried about the likely horrible misuses of a generalized stitching macro.

21:23 Scriptor: he might not want them to be too commonly used, it's more of an imperative construct

21:23 TimMc: People would compose large chunks of code using it, and Clojure would maybe even become known for being unreadable to newcomers because of them.

21:23 (worst-case scenario)

21:24 I would certainly rather have people name things.

21:24 Scriptor: I liked LearnYouAHaskell describing functional programming as defining more than describing steps, so stitching does the reverse of that

21:26 TimMc: Scriptor: Regarding imperative... one of Clojure's big selling points is easy Java interop, so easy imperative coding is actuallypretty important.

21:27 OK, I'm out for the night.

21:40 brweber2: is that a form of map that is not lazy? I know it is trivial to force the evaluation, but I'm wondering what the most idiomatic way is?

21:41 there, not that ... oops

21:48 tomoj: why?

21:48 clojurebot: why not?

21:48 tomoj: are you mapping with a side-effecting function?

21:58 nathanmarz: brweber2: (doall (map ...))

21:58 brweber2: tomoj exactly, I am mapping a side effecting function

21:59 tomoj: don't do that :(

21:59 brweber2: nathanmarz: thanks. That's what I have, I was just wondering if there was an existing function I didn't know about that does that

21:59 brehaut: brweber2: doseq is more common for side-effecty sequence stuff

21:59 tomoj: I prefer doseq, but if you're doall'ing it's not so bad since chunks won't bite you

22:00 brweber2: tomoj: brehaut: thanks!

22:01 brehaut: brweber2: it supports comprehension notation (like for) and has an implicit do

22:01 tomoj: &(->> (range) (map print) (take 3))

22:01 sexpbot: ⟹ (012345678910111213141516171819202122232425262728293031nil nil nil)

22:01 tomoj: that's what scares me

22:03 brweber2: tomoj: You've got the whole chunk of 32 there... it realized them all even though you only need three. Which function introduced the chunking in your example?

22:04 brehaut: brweber2: range

22:04 range and vectors are (currently) the only source (i think) of chunked seqs

22:04 tomoj: which means this weirdness can be hidden if you pass unchunked seqs, then pass a chunked seq in and bam

22:05 brweber2: yeah, i wish default chunk size was 1... and you had to explicitly change it

22:05 You'd still have this problem, but you'd have to introduce it yourself

22:06 brehaut: its very rarely a problem in real code

22:06 side effects are the major complication

22:06 (there is a niche of complex computations that are also bad with them, but they are rare)

22:07 tomoj: ackermann function or something?

22:08 brehaut: that sounds right

22:08 brweber2: brehaut: I simply prefer the easier to reason about solution as the default. Then again, I don't have to write a performant programming language, so I can espouse whatever naive opinions I may hold :)

22:08 brehaut: brweber2: the merits of both defaults were debated in great detail at the time it was implemted

22:09 brweber2: brehaut: I somewhat recall... I just haven't touched clojure in a while. Getting back into the swing ...

22:09 brehaut: chouser wrote an explicit dechunker function somewhere i recall

22:09 get back into seesaw, its nicer than straight swing

22:10 brweber2: brehaut: Oh no, not that SWING! haha I wouldn't touch that with a ten foot pole

22:15 dnolen: you easily can wrap ranges and vectors in a lazy-seq to defeat chunking.

22:16 brehaut: oh of course. clever

22:16 i had tried list, but i don tthink that works

22:17 brweber2: dnolen: are you sure?

22:17 dnolen: brweber2: not sure, positive.

22:18 brweber2: &(->> (lazy-seq (range)) (map print) (take 3))

22:18 sexpbot: ⟹ (012345678910111213141516171819202122232425262728293031nil nil nil)

22:18 brweber2: dnolen: is that what you meant? Learn me! Learn me! ;)

22:18 dnolen: brweber2: that's not what I'm calking about

22:18 brweber2: dnolen: Figured not since it doesn't seem to work. Which form do you mean?

22:20 dnolen: (defn lazier [x] (if x (lazy-seq (cons (first x) (lazier (next x))))))

22:23 brweber2: dnolen: Gotcha. That does the trick. Is that identical to the dechunker written by chouser mentioned before?

22:24 dnolen: brweber2: no, that solution involves deftype.

Logging service provided by n01se.net