2011-06-12
| 01: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? |
| 01:10 | tomoj | first, (java.awt.Color. 255 0 0) is more idiomatic (just some syntax sugar for what you wrote) |
| 01:10 | tomoj | &(apply #(java.awt.Color. %1 %2 %3) [255 0 0]) |
| 01:10 | sexpbot | ⟹ #<Color java.awt.Color[r=255,g=0,b=0]> |
| 01:11 | tomoj | ugly, but works |
| 01:11 | tomoj | 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 |
| 01:13 | tomoj | &(letfn [(color [[r g b]] (java.awt.Color. r g b))] (color [255 0 0])) |
| 01:13 | sexpbot | ⟹ #<Color java.awt.Color[r=255,g=0,b=0]> |
| 01:13 | tomoj | something like that could work too |
| 01: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?) |
| 02:42 | Scriptor` | hi everyone |
| 11:56 | mudge | hello |
| 11:56 | mudge | what is an "associative collection" ? |
| 11:57 | mudge | what does it mean if a data type is associative? |
| 12:03 | mudge | anybody here today? |
| 12:07 | mudge | hey halfprogrammer |
| 12:07 | mudge | hey, how do I found out if a value is a sequence or not? |
| 12:07 | halfprogrammer | Hi |
| 12:08 | halfprogrammer | (seq? BLAH) |
| 12:09 | halfprogrammer | mudge: when you say seq, among collections (list, vecotrs, map and set) (seq? X) returns true only for list |
| 12:09 | halfprogrammer | ,(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 | halfprogrammer | ,(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 | mudge | 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 | TimMc | 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 | mudge | i am reading somewhere that says that all collections can be treated as sequences |
| 12:14 | mudge | so I am wondering why all collections are not sequences if they can be treated as sequences |
| 12:15 | mudge | 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 | TimMc | ,(coll? (seq '(1 2 3 4))) |
| 12:17 | clojurebot | true |
| 12:17 | mudge | TimMc, yes I see that |
| 12:17 | mudge | 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 | halfprogrammer | that is why vectors and lists are sequential |
| 12:19 | halfprogrammer | 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 | mudge | ,(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 | __name__ | ,(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 | TimMc | 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 | TimMc | 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 | mudge | 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 | __name__ | 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 | TimMc | I have a file with a ? in its name. |
| 12:36 | __name__ | github is bugged |
| 12:36 | __name__ | 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 | TimMc | 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 | TimMc | hmmm... |
| 12:43 | TimMc | ,(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 | TimMc | 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 | TimMc | 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 | TimMc | 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 | manutter | 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 | TimMc | that's the job of the implicit syntax-quote that happens when you call a macro. |
| 13:20 | TimMc | ,`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 | TimMc | 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 | tomoj | is this not a counterexample: (defmacro foo [x] (namespace x)) (foo +) |
| 13:27 | TimMc | hrm |
| 13:27 | TimMc | maybe I am wrong! |
| 13:28 | TimMc | Blah, I guess I was confusing it with something else. |
| 13:28 | TimMc | 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 | TimMc | :-/ |
| 14:21 | TimMc | If you don't mind try/catch, there's Class/forName |
| 14:22 | TimMc | ,(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 | TimMc | Also, why do you need to reflect on this? |
| 14:43 | dnolen | TimMc: because ArityException doesn't exist in 1.2.0 |
| 14:43 | dnolen | 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 | dnolen | 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 | dnolen | 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 | mudge | 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 | TimMc | 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 | TimMc | 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 | leeda | 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 | tomoj | 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 | Tcepsa | Whoops, sorry >_< |
| 16:36 | TimMc | kephale: Yeah, that seems to work pretty well. clojure.string (or whatever) :as s, etc. |
| 16:37 | TimMc | 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 | mudge | ? |
| 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 | mudge | 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 | nickik | 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 | nickik | ,(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 | raek | 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 | void_ | Just used to C. |
| 18:42 | void_ | Anyway, I fixed it by redesigning. |
| 18:53 | mudge | (GET "/browse/*" request (let [[ns var] (str/split (get-in request [:params "*"]) #"/")] |
| 18:53 | mudge | (html |
| 18:53 | mudge | (layout |
| 18:53 | mudge | (namespace-browser (namespace-names)) |
| 18:53 | mudge | (var-browser ns (var-names ns)) |
| 18:53 | mudge | (var-detail ns var))))) |
| 18:53 | mudge | what is "request" in this: (GET "/browse/*" request (let [[ns var] (str/split (get-in request [:params "*"]) #"/")] |
| 18:53 | mudge | (html |
| 18:53 | mudge | (layout |
| 18:53 | mudge | (namespace-browser (namespace-names)) |
| 18:53 | mudge | (var-browser ns (var-names ns)) |
| 18:53 | mudge | (var-detail ns var))))) |
| 18:53 | mudge | ? |
| 18:53 | mudge | where does request come from? |
| 18:54 | raek | mudge: gist.github.com next time :) |
| 18:54 | raek | mudge: from whatever calls your handler with a request |
| 18:55 | raek | í.e. probably jetty |
| 18:55 | mudge | raek, okay, i will |
| 18:59 | mudge | what is this: #"/" |
| 18:59 | mudge | 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 | nickik | 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 | kephale | 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 | kephale | but, if you want to hassle them, a human has to carry its own energy store : P |
| 19:17 | kephale | 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 | nickik | 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 | nickik | 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 | mudge | anybody know what namespace the request function is in? |
| 19:45 | brehaut | mudge: clj-http |
| 19:45 | brehaut | 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 | brehaut | thrush is a function composition macro |
| 20:11 | brehaut | 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 | brehaut | 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 | brehaut | quotemstr: -?> might do what you want. its in contrib somewhere |
| 20:16 | brehaut | -?> |
| 20:16 | brehaut | ,-?> |
| 20:16 | clojurebot | java.lang.Exception: Unable to resolve symbol: -?> in this context |
| 20:16 | brehaut | clojure.contrib.core |
| 20:16 | brehaut | 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 | quotemstr | [mattb]: AIUI, Dalvik doesn't run Clojure code well. |
| 20:33 | [mattb] | ah |
| 20:33 | [mattb] | 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 | quotemstr | 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 | Scriptor | 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 | quotemstr | 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 | quotemstr | Of course, it's also possible that my sense for functional programming has been forever ruined by exposure to LOOP. :-) |
| 20:49 | quotemstr | 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 | Scriptor | 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 | quotemstr | 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 | quotemstr | tomoj: Ah, too bad. |
| 20:54 | quotemstr | 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 | quotemstr | TimMc: Any pointers? |
| 20:55 | TimMc | Sorry, no. |
| 20:55 | tomoj | quotemstr: what would explicit bindings look like? |
| 20:55 | tomoj | 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 | TimMc | I'd like to see his reasoning on that. |
| 20:57 | TimMc | 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 | tomoj | 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 | Scriptor | (look at the irc logs) |
| 21:02 | tomoj | http://groups.google.com/group/clojure/msg/1eb5cf8fa3248049 |
| 21:03 | tomoj | http://clojure-log.n01se.net/ |
| 21:04 | tomoj | that above the logs is rich on an arrow extension |
| 21:04 | tomoj | the rest of the discussion is pretty entertaining I think, crazy dude |
| 21:04 | tomoj | 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 | tomoj | oh |
| 21:05 | tomoj | 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 | TimMc | 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 | Scriptor | (sorry, clojure newb here) |
| 21:17 | TimMc | meh, you get the idea |
| 21:17 | TimMc | "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 | quotemstr | Nearly. Found the logs. |
| 21:22 | TimMc | I wonder where I saw it then. |
| 21:22 | TimMc | 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 | TimMc | (worst-case scenario) |
| 21:24 | TimMc | 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 | TimMc | 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 | brweber2 | 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 | brehaut | 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 | brweber2 | 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 | brehaut | side effects are the major complication |
| 22:06 | brehaut | (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 | brehaut | 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 | brehaut | 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. |