2009-11-24
| 00:00 | KirinDave1 | I'm trying to, as a way to get a handle on compojure |
| 00:00 | KirinDave1 | write a little program to track our foosball scores. |
| 00:01 | KirinDave1 | I'm writing things like make-player, make-game, add-player, add-game. |
| 00:02 | KirinDave1 | https://gist.github.com/3d800d9dfc8c437e548d |
| 00:02 | KirinDave1 | Is there a more elegant way to do this stuff? |
| 00:02 | KirinDave1 | Am I doing something that is already being done for me? |
| 00:04 | cark | well, using struct directly does the job, or better yet struct-map |
| 00:04 | cark | though in the long run it's good to have functions abstracting this |
| 00:04 | KirinDave1 | It seems like that'd be tedious is client code |
| 00:04 | KirinDave1 | Yeah |
| 00:04 | technomancy | structs are generally used as perf operations when you've profiled to find out that just plain maps aren't fast enough. |
| 00:04 | technomancy | s/operations/optimizations/ |
| 00:05 | KirinDave1 | technomancy: I'm mostly using them as a way of documenting the keys I expect. |
| 00:05 | cark | the one thing i don't like in your code : instead of having that many refs, you need a single one |
| 00:05 | cark | make a single *database* ref |
| 00:05 | cark | this will also be better for you to learn clojure |
| 00:05 | KirinDave1 | cark: I've thought about that, but wouldn't I also want the internal refs? |
| 00:05 | KirinDave1 | For the player history? |
| 00:06 | technomancy | KirinDave1: that works, but it generally ends up being more verbose. |
| 00:06 | KirinDave1 | There seems to be no reason to lock the entire DB if I want to update a single player. |
| 00:06 | cark | nope |
| 00:06 | _ato | cark: if you're going to have a single database ref, it may as well be an atom |
| 00:06 | KirinDave1 | Right. |
| 00:06 | technomancy | KirinDave1: also: if you're not doing anything in a dosync except commuting, consider atoms |
| 00:06 | cark | KirinDave : you will mostly be reading, writing only happens once a game is played |
| 00:06 | technomancy | since you're not really taking advantage of the ACI properties of transactions |
| 00:06 | KirinDave1 | technomancy: I will be doing alters for other stuff. |
| 00:06 | technomancy | KirinDave1: I mean if you're only doing a single write per transaction |
| 00:07 | _ato | presumably there will cases later on where you want to atomically change team's wins as well the games or history together |
| 00:07 | KirinDave1 | Yeah |
| 00:07 | cark | _ato : right, but what if you add more stuff later and need to coordinate ? |
| 00:07 | KirinDave1 | The stuff that involves adding a game and then updating the history, and the ladder, will involve multiple changes in a single transation |
| 00:08 | technomancy | that's true; I guess you are planning ahead for stuff that isn't there yet |
| 00:08 | KirinDave1 | Yes |
| 00:08 | arohner | why do you guys advocate a single ref? I've always thought of using a ref for each thing with identity that can change |
| 00:08 | cark | that's a trade-off, this database is small, it doesn't need such granualirty |
| 00:08 | arohner | and IMO smaller refs are easier to manipulate than reaching N levels into a tree structure to alter one node |
| 00:08 | cark | granularity |
| 00:09 | cark | not at all, using clojure it's easy to reach deep |
| 00:09 | arohner | it's still more work than not reaching deep |
| 00:10 | cark | allright, what if you suddenly need to keep track of some other games, say fifa for instance |
| 00:10 | KirinDave1 | Well I'd probably abstract a top level databse. |
| 00:10 | KirinDave1 | But I wouldn't make that a ref, i don't think. |
| 00:10 | KirinDave1 | That structure would be immutable, it'd have keys |
| 00:10 | cark | so you need to go back in your code and change it all |
| 00:10 | KirinDave1 | Its key's values would be mutable. |
| 00:10 | arohner | not at all |
| 00:11 | KirinDave1 | I suppose. I was thinking maybe a database binding. |
| 00:11 | arohner | take this current code, add another ref on top of it, for the "league" |
| 00:11 | arohner | the league ref points at a set of games |
| 00:12 | KirinDave1 | Well I'd have to refactor those direct refs. :) |
| 00:12 | KirinDave1 | players, teams, games, etc |
| 00:12 | technomancy | KirinDave1: the only other thing I'd note is that when you have multiple arg lists, it's more common to have the fewer-arg versions call the more-arg versions, filling in the missing args. |
| 00:12 | _ato | cark: there's no point in Clojure's STM if you're just using a single top-level database ref. You're not taking advantage of concurrency. While it's true this is a simple app so it doesn't need concurrency I think KirinDave1 is using it as an excercise to learn about Clojure's features |
| 00:12 | technomancy | minor point, but it ends up being a little more dry |
| 00:13 | KirinDave1 | technomancy: Good point. |
| 00:13 | cark | ato : in a real life program you'll have more than this single database |
| 00:13 | KirinDave1 | cark: wouldn't I just make the database anargument in the functions? |
| 00:13 | cark | each time you use a ref, you loose the nice characteristics of purely functional programing |
| 00:13 | KirinDave1 | instead of a top ref? |
| 00:14 | cark | KirinDave : yes, that's even better |
| 00:14 | cark | but at some point you need a ref or an atom to hold the identity of your state |
| 00:14 | KirinDave1 | cark: Right, well I may go back to that. |
| 00:14 | KirinDave1 | That should be in client code tho. |
| 00:14 | KirinDave1 | Not this lib. |
| 00:14 | KirinDave1 | I should ahve a make-league function that drops a league out that you could keep. |
| 00:15 | cark | well you must stop at some point |
| 00:15 | KirinDave1 | I will in my compojure client code |
| 00:15 | cark | what about adding planet mars leagues ? |
| 00:15 | KirinDave1 | probably an atom |
| 00:15 | KirinDave1 | I was considering using a binding-able variable instead of a calling argument |
| 00:15 | KirinDave1 | Is that a shitty idea? |
| 00:15 | KirinDave1 | I see people use bindable vars all the time in contrib, but I hear a lot of grumbling about it here. |
| 00:16 | cark | well no it's not a bad idea, arguments are more readily readable tho |
| 00:16 | hiredman | *grumble* *grumble* |
| 00:16 | cark | this var binding stuff is good when there are many arguments that almost never change |
| 00:16 | technomancy | KirinDave1: you run into trouble when you create a lazy seq within binding that gets consumed outside the binding form |
| 00:17 | cark | like the *print-blahblah* vars for instance |
| 00:17 | _ato | the other problem with bindables is if you want to deal with two leagues in the same function you end up having to (with-league l1 ...) (with-legaue l2 ...) around every call anyway |
| 00:17 | cark | ahyes and one last recommendation : those toplevel vars should be named like this : *player* *teams* |
| 00:18 | cark | that's a convention people use |
| 00:21 | KirinDave1 | cark: I though that was a convention for things that would be bound, but sure. |
| 00:24 | cark | you'll run into another problem |
| 00:25 | cark | you have players in teams and in players |
| 00:25 | KirinDave1 | ? |
| 00:25 | KirinDave1 | What's the problem with that? |
| 00:25 | KirinDave1 | The players are a set and I intend to only use players from the players set |
| 00:25 | cark | so if you change a player, you need to update both its team and the players database |
| 00:26 | cark | so that's where you might want to make refs of those players |
| 00:26 | KirinDave1 | Does identity propagate through refs? |
| 00:26 | KirinDave1 | Seems like sets would get very irritated at that. :) |
| 00:27 | _ato | ,#{(ref 1) (ref 1)} |
| 00:27 | clojurebot | #{#<Ref@d41010: 1>} |
| 00:27 | KirinDave1 | Wow, that's neat. |
| 00:27 | _ato | that's... weird |
| 00:27 | KirinDave1 | I mean, the thing is. |
| 00:27 | _ato | I wonder what happens then if you change one of them |
| 00:27 | KirinDave1 | Yeah |
| 00:27 | cark | well when you populate a player struct, you get a _value_ |
| 00:27 | KirinDave1 | that's just what I was wondering |
| 00:27 | cark | when you put this value in a ref, you get identity |
| 00:28 | cark | ato : yes that's very weird =/ |
| 00:28 | cark | and i wouldn't rely on that |
| 00:29 | arohner | that seems like a bug |
| 00:29 | arohner | ,(ref 1) |
| 00:29 | clojurebot | #<Ref@e4bf0e: 1> |
| 00:29 | arohner | ,(ref 1) |
| 00:29 | clojurebot | #<Ref@b2d6bd: 1> |
| 00:30 | _ato | ,(let [s #{(ref 1) (ref 2)}] (dosync (ref-set (first s) 2)) s) |
| 00:30 | clojurebot | #{#<Ref@86c645: 2> #<Ref@e9ff86: 1>} |
| 00:30 | _ato | ,(let [s #{(ref 1) (ref 2)}] (dosync (ref-set (first s) 1)) s) |
| 00:30 | clojurebot | #{#<Ref@596d65: 1> #<Ref@11d1bb6: 2>} |
| 00:30 | cark | KirinDave : or you could make your player database a map, and store the key in other places |
| 00:31 | KirinDave1 | So players mapped by name, you suggest? |
| 00:31 | _ato | ,(let [s #{(ref 1) (ref 2)}] (dosync (doseq [r s] (ref-set r 1))) s) |
| 00:31 | clojurebot | #{#<Ref@ed4107: 1> #<Ref@39e50f: 1>} |
| 00:31 | cark | if you're sure these are unique =) |
| 00:31 | KirinDave1 | I suppose. |
| 00:31 | _ato | ,(set (let [s #{(ref 1) (ref 2)}] (dosync (doseq [r s] (ref-set r 1))) s)) |
| 00:31 | clojurebot | #{#<Ref@e32bd0: 1> #<Ref@516c52: 1>} |
| 00:31 | KirinDave1 | The only part of a player that can change is its history, tho |
| 00:31 | KirinDave1 | And that's what's ref'd and shared throughout all the databases. |
| 00:31 | _ato | ,[(ref 1) (ref 1)] |
| 00:31 | clojurebot | [#<Ref@1bda30a: 1> #<Ref@11b0d65: 1>] |
| 00:31 | KirinDave1 | So long as I make sure to populate teams with entries from *players* |
| 00:31 | _ato | :\ |
| 00:32 | arohner | _ato: that's weird |
| 00:32 | KirinDave1 | Yeah I'm not sure that's so awesome |
| 00:33 | cark | well try it, you'll see a bug where you have the old value still in team once you updated the player in players |
| 00:33 | _ato | ,(apply hash-set (let [s #{(ref 1) (ref 2)}] (dosync (doseq [r s] (ref-set r 1))) s)) |
| 00:33 | clojurebot | #{#<Ref@759e62: 1> #<Ref@1f16253: 1>} |
| 00:33 | _ato | ,#{(ref 1) (ref 1)} |
| 00:33 | clojurebot | #{#<Ref@1436fa7: 1>} |
| 00:33 | _ato | ,(hash-set (ref 1) (ref 1)) |
| 00:33 | clojurebot | #{#<Ref@5b4583: 1> #<Ref@30ac0d: 1>} |
| 00:33 | _ato | eh... |
| 00:33 | _ato | ,(array-set (ref 1) (ref 1)) |
| 00:33 | clojurebot | java.lang.Exception: Unable to resolve symbol: array-set in this context |
| 00:34 | arohner | I would model this so every player is a ref, every game is a ref |
| 00:34 | arohner | everything that wants to talk about players or games will point at that ref |
| 00:34 | arohner | so there's no possibility of having two copies of a player, and things won't get inconsistent |
| 00:35 | KirinDave1 | Um, but players are immutable except for thier history. |
| 00:35 | KirinDave1 | So what could change? |
| 00:35 | cark | right tradeoffs again, it makes sense here |
| 00:35 | arohner | so? |
| 00:35 | arohner | their histories change |
| 00:36 | cark | if their history change, their value change, so that's a completely new player |
| 00:36 | arohner | that's a new player *struct* |
| 00:36 | arohner | conceptually, the ref is the player |
| 00:37 | cark | that's a new player value =) conceptually his identity is the ref =) |
| 00:37 | KirinDave1 | Well, conceptually his history is the ref |
| 00:37 | KirinDave1 | I mean I could do away with history alltogether and just calculate it on the fly with games |
| 00:38 | KirinDave1 | I was just going to keep it caches |
| 00:38 | KirinDave1 | err, cached. |
| 00:39 | KirinDave1 | But I'll consider changing it. |
| 00:40 | cark | anyways you have 2 options to give your players an identity, either you give them a unique key or you put them in a ref, and i'm off to bed ! |
| 00:40 | cark | gnight |
| 01:04 | rads | is there a concise way to turn something like [["a" 1] ["b" 2] ["c" 2] ["a" 2] ["b" 3]] into {"a" 3, "b" 5, "c" 2}? (find the sums) |
| 01:06 | _ato | ,(apply merge-with + (map hash-map [["a" 1] ["b" 2] ["c" 2] ["a" 2] ["b" 3]])) |
| 01:06 | clojurebot | java.lang.RuntimeException: java.lang.IllegalArgumentException: No value supplied for key: ["a" 1] |
| 01:06 | _ato | ,(apply merge-with + (map #(apply hash-map %) [["a" 1] ["b" 2] ["c" 2] ["a" 2] ["b" 3]])) |
| 01:06 | clojurebot | {"a" 3, "b" 5, "c" 2} |
| 01:07 | _ato | rads: ^ |
| 01:07 | rads | _ato: thank you. the flexibility of clojure's sequence library never ceases to impress me |
| 01:36 | rads | how would I double each value in a hash map? |
| 01:52 | tomoj | ,(into {} (for [[k v] {:foo 3 :bar 6 :baz 9}] [k (* 2 v)])) |
| 01:52 | clojurebot | {:foo 6, :bar 12, :baz 18} |
| 01:52 | tomoj | rads: ^ |
| 02:04 | rads | tomoj: thanks |
| 02:08 | _ato | ,(use 'clojure.contrib.generic.functor) |
| 02:08 | clojurebot | nil |
| 02:08 | _ato | ,(fmap #(* % 2) {:foo 3 :bar 6 :baz 9}) |
| 02:08 | clojurebot | {:foo 6, :bar 12, :baz 18} |
| 02:09 | _ato | ,(fmap #(* % 2) [3 6 9]) |
| 02:09 | clojurebot | [6 12 18] |
| 02:09 | tomoj | cool |
| 02:10 | tomoj | is that any faster? or just prettier? |
| 02:10 | _ato | just prettier, it's implemented in terms of (into {} ...) IIRC |
| 02:13 | _ato | ~def fmap |
| 02:14 | _ato | heh, yeah: (into (empty m) (for [[k v] m] [k (f v)]))) |
| 02:14 | _ato | ~def into |
| 02:15 | _ato | doing a reduce might be slightly faster as it avoids the lazyseq but probably not enough to be worth the trouble |
| 02:18 | tomoj | I wonder if a transient map could do it faster? |
| 02:18 | _ato | "into" uses a transient map |
| 02:18 | tomoj | well, I meant take the original map, make it transient, and then replace the keys |
| 02:19 | tomoj | er, values |
| 02:19 | _ato | oh right |
| 02:19 | tomoj | to avoid building up the structure again, dunno if that'd help or is possible |
| 02:20 | _ato | hmm, not sure. it'd have to copy all keys and values anyway, so perhaps not, but there might some weird cache locality benefits or something |
| 02:28 | tomoj | hmm |
| 02:28 | tomoj | I think it might actually be a bit faster |
| 02:28 | tomoj | but not much |
| 02:28 | tomoj | comparing (defn trans-map [f m] (let [t (transient m)] (doseq [k (keys m)] (assoc! t k (f (get t k)))) (persistent! t))) |
| 02:28 | tomoj | and (defn trans-map2 [f m] (into {} (for [[k v] m] [k (f v)]))) |
| 02:29 | tomoj | I wish the 'time' macro returned the time instead of printing it :/ |
| 02:30 | _ato | yeah, you should be seeing at least a slight advantage from the lack of the lazyseq that 'for' returns |
| 02:30 | _ato | oh hang on.. |
| 02:30 | _ato | err... you can't use a transient that |
| 02:31 | _ato | way |
| 02:31 | _ato | it'll break |
| 02:31 | _ato | at least it's not guaranteed to work anyway |
| 02:31 | _ato | I wouldn't rely on it |
| 02:34 | tomoj | huh? |
| 02:35 | tomoj | how would it break? |
| 02:35 | hiredman | tomoj: you read http://clojure.org/transients ? |
| 02:36 | hiredman | "Don't bash in place" |
| 02:36 | hiredman | the flow is just like with the persistent versions, you have to pass around the result of operations |
| 02:36 | tomoj | oh yes |
| 02:36 | tomoj | so I should be reducing I guess |
| 02:37 | _ato | yeah |
| 02:39 | _ato | something like (persistent (reduce (fn [m [k v]] (assoc! m k (f v))) (transient! m) m)) |
| 02:39 | _ato | though I suspect (persistent (reduce (fn [m [k v]] (assoc! m k (f v))) (transient! {}) m)) would be just as fast |
| 02:39 | tomoj | well that's what my initial wonder was, really |
| 02:39 | tomoj | I always feel bad starting from {} and rebuilding |
| 02:40 | tomoj | the hash structure stays the same since the keys aren't changing, so it seems like it would be faster to just swap out all the values |
| 02:45 | _ato | hmm, looks like you might be right, but the effect is only worth 5 or 10% at least on my PC |
| 02:45 | tomoj | not worth the bother then |
| 02:49 | tomoj | yeah I just got a 5% speedup too |
| 04:47 | kzar | Is there a way to pass extra parameters to the JPanel repaint function? I want to pass the information needed to render the game's state. |
| 04:50 | scottj_ | I haven't used Swing much but from the java docs it doesn't look like that's what repaint is for |
| 04:50 | liwp | kzar: huh? repain() sends an event to the Swing event handler asking for a repaint of that component. It has nothing to do with your game state |
| 04:52 | kzar | liwp: Yea, my game's running from a loop and when I call repaint it ends up calling the function I wrote to render the game. I wanted to pass details of the state through repaint, so it reached my render function. That way the code would be more functional then having a variable set outside the game loop |
| 04:54 | kzar | I'm not sure that's possible or if there's an alternative way to acheive a similar result. |
| 04:54 | liwp | kzar: your functions has to be a method of a class for it to work with swing, so I think your only option is to embed the game state in your instance of that class |
| 04:55 | tomoj | isn't repaint called when the user moves the window around? |
| 04:55 | tomoj | or resizes, etc? |
| 04:55 | liwp | kzar: fundamentally swing is an OO framework, so I think you'll just run into a lot of trouble if you try to shoehorn it into FP thinking |
| 04:55 | liwp | tomoj: yes, but you can also call it yourself to force a redraw |
| 04:55 | tomoj | whatever's calling repaint when the window is resized shouldn't have to know the gamestate, though |
| 04:55 | liwp | agreed |
| 04:56 | kzar | oh that's a good point |
| 04:56 | tomoj | wouldn't you just have a proxy that uses paint to access the gamestate and draw it? |
| 04:56 | tomoj | and then if someone wants to repaint it they just ask? I still don't really understand swing very well :/ |
| 04:57 | liwp | kzar: what you can do it write another function that is purely functional and returns the new game state based on the old game state, and call this function from your implementation of the function that swing calls |
| 04:57 | liwp | that way you do have a nice purely functional game state updater |
| 04:57 | kzar | liwp: But where does it get the old game state from? |
| 04:58 | liwp | kzar: you must implement a class that inherits one of the swing base classes, right? |
| 04:58 | liwp | (it's been a while since I've done any swing) |
| 04:58 | liwp | so your game state would be a field of that class |
| 04:58 | tomoj | seems strange to me to update the gamestate based on what swing wants |
| 04:59 | kzar | tomoj: Yea that's not what I want |
| 04:59 | tomoj | I want my gamestate in a ref/atom and the gui component will just deref this and paint whatever's there |
| 05:00 | liwp | sure, so your function would be something like (defn my-fun [#^Graphics g] (let [s @state] <paint>))? |
| 05:01 | liwp | I gotta run, but I think tomoj's right, you should use refs |
| 05:01 | kzar | ok |
| 06:07 | krumholt_ | can i make a collection from a java array? |
| 06:10 | hoeck1 | krumholt_: just call seq on it |
| 06:11 | krumholt_ | hoeck1 nice thanks |
| 06:16 | AWizzArd | chouser: shell-outs sh is for short running processes yes? (not like a pipe) |
| 07:01 | djpowell | hmm, you know how add-class-path doesn't work well cause it can't append to the system class path? Attach agents, like I use in my liverepl can. Wonder if you could use them to replace the interactive uses of add-class-path? <http://java.sun.com/javase/6/docs/jdk/api/attach/spec/com/sun/tools/attach/VirtualMachine.html#loadAgent(java.lang.String, java.lang.String)> |
| 07:01 | djpowell | probably not. sounds flakey. |
| 07:23 | djork | djpowell: what's your liverepl? |
| 07:28 | _ato | djpowell: it's likely the agent is loaded in a subclassloader, so it would probably have the same problems as add-classpath (namely stuff loaded in higher classloaders can't see stuff in lower classloaders) |
| 07:29 | _ato | add-classpath should work okay if you load everything into Clojure's classloader (ie you put nothing but the clojure jar on the -cp command-line and add every jar you need with add-classpath) |
| 07:31 | esj | gents, is there a way to send a SIGINT (or equivalent) to a particular agent. shutdown-agents merely prevents new actions being dispatched, while I want to pull-down the running action. |
| 07:33 | krukow | esj: I don't think so, you'd have to program the agent to be interruptible |
| 07:33 | krukow | and check for interrupt status often |
| 07:33 | krukow | and still you'd need to access the thread... so probably not :-( |
| 07:34 | esj | ok thanks |
| 07:36 | _ato | yeah, not reliably anyway. Even if you can get a handle on the thread (I guess you could have the agent put it in a ref when it starts the job or something), if it blocks on IO or something catches the interrupt exception it becomes uninterruptible |
| 07:39 | mrSpec | Could you tell me how to change the value of x in let block? I cant find anything :/ like: (let ((x 0)) (setf x 1)) |
| 07:40 | krukow | you cant: let bound locals are not variables |
| 07:40 | _ato | mrSpec: clojure locals are immutable |
| 07:40 | esj | hmm... will need to think. |
| 07:41 | krukow | there was one thing that came up yesterday: you can (let [x 42 x (inc x)] x) |
| 07:41 | _ato | you can however do: (let [x 0] (let [x 1] ...)) |
| 07:41 | _ato | yeah |
| 07:41 | krukow | LOL :-) |
| 07:41 | krukow | ,circuitbreak |
| 07:41 | clojurebot | java.lang.Exception: Unable to resolve symbol: circuitbreak in this context |
| 07:41 | esj | yikes ! |
| 07:41 | _ato | that's not changing the value though, it's creating a new binding that "shadows" the outer one |
| 07:41 | mrSpec | hehe |
| 07:41 | krukow | ,(let [x 42 x (inc x)] x) |
| 07:41 | clojurebot | 43 |
| 07:41 | krukow | that is what I mean |
| 07:42 | mrSpec | but can I do it in other way? to change value? |
| 07:42 | Maddas | Why? |
| 07:42 | mrSpec | I dont want 2nd "x" |
| 07:42 | Maddas | What is the problem you're trying to solve? You can't mutate an immutable, that's kinda the point :-) |
| 07:42 | krukow | why do you want to change it: can you give an example? |
| 07:43 | mrSpec | ok, I'm rewriting C++ code |
| 07:43 | mrSpec | I'll paste it sec |
| 07:43 | djpowell | djork: http://github.com/djpowell/liverepl - lets you repl in to running clojure/java processes with no special pre-configuration |
| 07:43 | krukow | heh - ok here we go |
| 07:43 | djork | oh cool |
| 07:44 | mrSpec | ,paste |
| 07:44 | clojurebot | java.lang.Exception: Unable to resolve symbol: paste in this context |
| 07:44 | mrSpec | hmm |
| 07:44 | mrSpec | what was the url? |
| 07:44 | djork | clojurebot: paste |
| 07:44 | clojurebot | lisppaste8, url |
| 07:44 | lisppaste8 | To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste. |
| 07:44 | mrSpec | thanks |
| 07:44 | krukow | clojurebot: help |
| 07:44 | clojurebot | http://www.khanacademy.org/ |
| 07:44 | djork | mrSpec: to "change" the value of a binding in a block you would recur |
| 07:45 | djork | either recur on the fn itself or use the loop construct |
| 07:45 | lisppaste8 | mrSpec pasted "Mandelbrot " at http://paste.lisp.org/display/91009 |
| 07:46 | djork | ,(loop [x 1] (if (< x 10) (recur (inc x)) x) |
| 07:46 | clojurebot | EOF while reading |
| 07:46 | djork | oops |
| 07:46 | djork | ,(loop [x 1] (if (< x 10) (recur (inc x)) x)) |
| 07:46 | clojurebot | 10 |
| 07:46 | krukow | C for usually maps to loop-recur |
| 07:46 | krukow | or higher order functions |
| 07:47 | djork | mrSpec: you wouldn't "change" isInside, you would return it |
| 07:47 | mrSpec | so if it so complicated, I'm doing something wrong? |
| 07:47 | mrSpec | djork: ah |
| 07:47 | esj | yeah, i think recrusion |
| 07:48 | djork | your innermost for loop should be translated into one expression that evaluates to the value of is-inside |
| 07:49 | krukow | mrSpec: it is not really more complicated, just different |
| 07:49 | mrSpec | djork: ok, I'll try with loop |
| 07:49 | krukow | but don't measure performance and then come back saying that clojure is slow :-) |
| 07:49 | djork | heh |
| 07:51 | mrSpec | hah about speed... I have some memory problem. It takes a lot of memory, but first I'll make it work, then I will think about memory ;) |
| 07:51 | krukow | ;-) btw. I think that algorithm will be awkward to translate |
| 07:52 | krukow | particularly the part that sets isInside to false and then checks it later to sideeffect putpixel |
| 07:55 | mrSpec | krukow: so I should find other algorithm? ;) |
| 07:57 | krukow | I think it would be easier to rethink the algorithm than to try and port that imperative algorithm to a functional style, but just my two cents :-) |
| 07:59 | _ato | http://gist.github.com/241856 |
| 08:00 | _ato | the isInside loop might look something like that I guess |
| 08:00 | _ato | I don't know what the alrogithm is doing so I've just called it "step" |
| 08:01 | djork | I'd make the algo return a seq of coords |
| 08:04 | mrSpec | _ato: thanks, I'll try it :D |
| 08:05 | _ato | I guess you'd probably need to use letfn instead of defn for step and inside? as you need to close over c-im and c-re values from the outer loops |
| 08:06 | mrSpec | i will have to read about letfn to see the difference. |
| 08:06 | _ato | oh actually inside? is okay |
| 08:06 | _ato | it's just step that uses c-im and c-re |
| 08:10 | _ato | yeah.. so actually maybe the whole thing would look something more like this: http://gist.github.com/241856 (updated) |
| 08:10 | mrSpec | ok, thanks for help, I have to go to Uni BBL |
| 08:11 | krukow | heh - uni exercise :-) |
| 08:14 | AWizzArd | rhickey: when I (send my-agent) in two threads T1 and T2, will then an await or await-for in T1 always wait for the answer it sent? |
| 08:16 | the-kenny | AWizzArd: I think t1 will wait for *all* actions in the agent to complete |
| 08:17 | AWizzArd | So then I would need to keep my current strategy to provide a (promise) and read that, ok. |
| 08:56 | rhickey | so I've just applied a contributed patch with git am, and tests fail, what's the easiest way to back it out? |
| 08:57 | chouser | you haven't pushed it? |
| 08:57 | rhickey | no |
| 08:57 | chouser | git reset --hard HEAD^ # that'll back you up one commit |
| 08:57 | chouser | the --hard means you might lose data, but of course that's what you want. |
| 08:57 | chouser | just be careful you don't have any uncommitted changes you want to keep |
| 08:58 | rhickey | I thought so, what an ugly command for such an ordinary thing |
| 08:58 | chouser | well, it's what I do. I don't know if it's "right" or best |
| 08:58 | rhickey | since git am applications are always speculative, you are not committing something you wrote yourself and understand to be correct |
| 09:02 | chouser | yes. I think another option might be to do all such commits in a local branch made for just such activity |
| 09:03 | chouser | but it's not clear to me that whole set of commands you'd end up using would be any less wordy |
| 09:03 | rhickey | chouser: I do that, but there were prior patches I wanted to keep |
| 09:04 | rhickey | ok, next release punch list is down to three items |
| 09:06 | chouser | ooh |
| 09:06 | rhickey | agent errors needs tidying |
| 09:07 | rhickey | sorted-set-by patch is broken, but I'd like to get the fix in |
| 09:07 | chouser | embedded constants is just about the tests. |
| 09:07 | chouser | need to make sure they're actually testing what they claim to be |
| 09:08 | rhickey | I'm unclear about embedded constants, don't we have that already? |
| 09:08 | chouser | yeah, the main patch is in but there's been some confusion about the tests. |
| 09:09 | chouser | at least in part because my experience reading tests is thin |
| 09:11 | rhickey | I've looked t every patch, and determined it's either not yet a good idea or not ready (in backlog), a good idea for next time (approved backlog), applied it, or those 3 left in Next Release |
| 09:14 | chouser | thank you. Does this feel like a sane system to repeat for future releases? |
| 09:15 | rhickey | I think so, we'll see how people do with the latest code and release candidate downloads |
| 09:17 | chouser | almost 30% so far say they're using 1.0. I'm losing my bet. |
| 09:17 | rhickey | we are going to need docs for a lot of things |
| 09:17 | chouser | yeah, I thought of that. :-/ |
| 09:17 | rhickey | where are the results? |
| 09:17 | chouser | no good result charts yet |
| 09:18 | chouser | I was just using this: http://tinyurl.com/yefmz8e |
| 09:19 | rhickey | thanks |
| 09:19 | chouser | almost 10% on 'new' |
| 09:20 | rhickey | crazy people |
| 09:20 | rhickey | :) |
| 09:20 | chouser | :-) |
| 09:20 | fogus_ | chouser: Hey! I resemble that remark. |
| 09:21 | rhickey | so new is very new today - the direct linking stuff is in for the craz... er intrepid |
| 09:21 | the-kenny | How can I take the survey? I can't find a link in the Spreadsheet.. |
| 09:21 | fogus_ | I don't know what that word means, but it sounds great! |
| 09:22 | chouser | 53% don't know what chunked seqs are |
| 09:22 | chouser | the-kenny: survey: http://tinyurl.com/yeejwok |
| 09:23 | chouser | 1% say chunked seqs hurt |
| 09:26 | devlinsf | ,(str "Test") |
| 09:26 | clojurebot | "Test" |
| 09:51 | cemerick | rhickey: been absent for a bit -- is this 'direct linking' written up anywhere, or are the irc logs the best spot? |
| 10:08 | jweiss | question - is it idiomatic or overkill to use a multimethod like a switch statement? I am not sure that's an intended use for multimethods |
| 10:08 | krumholt_ | can i "clear" a namespace of all symbols? i am trying to compile my code and i have renamed a bunch of functions. the "old" version are still around and i need to get rid of them |
| 10:09 | chouser | jweiss: if there's a possibility someone else might want to extend your switch statement, multimethods are definitely a good option |
| 10:09 | jweiss | chouser: probably not going to need extending |
| 10:09 | chouser | jweiss: if not then I guess it's up to you whether you think it would be clearer using cond or condp, or if multimethods would be clearer. |
| 10:11 | jweiss | chouser: i'll try the multimethod and see if it looks readable. thanks |
| 10:11 | chouser | jweiss: of course anytime the cond wouldn't be at the top level of a fn, a multimethod is likely to be a poor fit. |
| 10:12 | chouser | krumholt_: you can combind ns-interns with ns-unmap to clear everything |
| 10:13 | jweiss | chouser: i'm trying to "switch" on a test result (pass/fail/skip/exception) and call a set of "listeners" which do user-defined stuff based on the results of the test |
| 10:13 | jweiss | this is not any of the build in test stuff btw |
| 10:13 | jweiss | built |
| 10:14 | jweiss | i think multimethod will work |
| 10:14 | krumholt_ | chouser, thanks |
| 10:28 | scottj_ | Is there a general pattern for converting (for [a (foo) b (bar a) c (baz b)] [a b c]) into a series of maps? I'm trying to generalize p27 from ninety-nine prolog probs, here is the specific solution I came up with http://paste.lisp.org/display/91015 any suggestions? thanks |
| 10:31 | chouser | what's wrong with using 'for'? |
| 10:34 | scottj_ | in part I'm curious how to do it w/ map, since I could use pmap. in part bc I thought map might be easier to write a general solution for w/o macros. |
| 10:34 | chouser | hm, maybe we need pfor. :-) |
| 10:35 | jweiss | if i'm using a multimethod that takes 3 args, and the dispatch only cares about the first arg, what do i put for the 2nd and 3rd args in the defmethods? |
| 10:37 | jweiss | just use nil? |
| 10:40 | chouser | scottj_: http://paste.lisp.org/display/91015#1 |
| 10:41 | chouser | scottj_: when you have :when or :while things get trickier. |
| 10:42 | scottj_ | Chousuke: thanks! |
| 10:42 | scottj_ | (sorry about the default autocorrect) |
| 10:42 | scottj_ | or maybe that was tab |
| 10:42 | chouser | np |
| 10:43 | chouser | happens all the time |
| 10:43 | chouser | but we're each too stubborn to change our nicks, so there you go. :-) |
| 10:44 | rhickey | cemerick: IRC logs re: direct linking - new last weekend |
| 10:47 | cemerick | OK, thanks :-) |
| 10:48 | cemerick | +1 on the idea of pfor |
| 10:48 | rhickey | cemerick: short story - more speed, via dynamicity tradeoff - nothing new under the sun |
| 10:49 | cemerick | rhickey: yeah, I caught a brief bit of the conversation yesterday, w.r.t. issues with contrib ns' rebinding core fns |
| 10:49 | rhickey | but open questions about how to best expose/control, so please chime in once up to speed |
| 10:49 | chouser | apparently I have an unconcious urge to make 'for' as complex as possible. chunk support helped a lot. pfor would take it a significant step further. |
| 10:50 | cemerick | I actually do rebind the root of a couple of core vars, though I presume that wouldn't be impacted by dynamic linking. |
| 10:50 | cemerick | or, static linking, that is. |
| 10:51 | cemerick | chouser: for is the new LOOP? :O |
| 10:51 | rhickey | cemerick: meaning you replace the core fn? |
| 10:51 | chouser | cemerick: if you don't call it, it won't be staticly linked |
| 10:51 | rhickey | I'd like to call it direct linking |
| 10:51 | chouser | cemerick: if you don't call it, it won't be direct linked |
| 10:52 | cemerick | rhickey: yeah -- the memoization of classes, or bases (forget which) |
| 10:52 | chouser | ah |
| 10:52 | cemerick | ah, supers and bases |
| 10:52 | rhickey | but yes, replacing roots would be effected since code direct linked prior to the replacement won't see the new version |
| 10:52 | rhickey | affected |
| 10:53 | cemerick | rhickey: I make sure I do my monkey-patching very, very early :-) |
| 10:54 | rhickey | I'm interested in any early experience reports on the latest new with direct linking |
| 10:54 | cemerick | I'm bundling a release this week -- will hopefully pull in HEAD over the weekend. |
| 10:54 | cemerick | rhickey: you're expecting some pretty crazy perf improvements eh? |
| 10:55 | rhickey | cemerick: it seems like 20-25% across the board is easy, but in specific cases it can be much. much faster, like 10x + |
| 10:56 | rhickey | right now it is limited to clojure*, so you won't get direct links for your own code |
| 10:56 | cemerick | is there more going on here than simply avoiding the indirection of the vars? |
| 10:57 | rhickey | cemerick: it's not actually the indirection, its the volatility |
| 10:57 | rhickey | can't inline through volatile |
| 10:57 | cemerick | you mean all the stuff associated with binding... |
| 10:57 | cemerick | oh, you mean java-volatile |
| 10:57 | rhickey | cemerick: no, dynamic binding is another layer, I'm just talking about replaceable roots |
| 10:58 | chouser | rhickey: re agent errors, you want some kind of guard to prevent any thread from doing clear-agent-errors while a error handler is running? |
| 10:58 | chouser | rhickey: or just guard the error handler thread itself while the handler is running? |
| 10:59 | rhickey | chouser: if easy, which it could be since you could compare *agent* to passed agent |
| 10:59 | rhickey | but most important is to doc that it is not ok |
| 11:00 | rhickey | until we figure out that it is :) |
| 11:00 | chouser | so other threads clearing while handler is running is ok |
| 11:00 | cemerick | so, without looking at HEAD (:-P ), I'm guessing there's now two Var classes, one with a volatile root another without -- and a direct-linked call site gets the latter, everyone else gets the former... |
| 11:00 | chouser | :-) right |
| 11:00 | rhickey | cemerick: no, direct linking is a property of the caller, not the var |
| 11:00 | cemerick | swing-and-a-miss |
| 11:00 | rhickey | so different callers might have different linkage |
| 11:01 | rhickey | the only thing that *is* on the var currently is a :dynamic true metadata tag that indicates it should never be direct-linked as it is due to be rebound by design |
| 11:01 | rhickey | currently pr is marked thusly for pprint |
| 11:02 | rhickey | and test/report |
| 11:03 | chouser | sorry, I'm still not clear on what you want for clear-agent-errors. (send a (fn [_] (clear-agent-errors *agent*))) is ok, right? |
| 11:04 | rhickey | chouser: why would one do that? |
| 11:05 | cemerick | nuclear-level error clearing "I want a usable agent back, dammit!" |
| 11:05 | rhickey | cemerick: but the send part? |
| 11:06 | cemerick | *shrug* |
| 11:06 | chouser | actually that won't work because you can't send to an agent with errors |
| 11:06 | cemerick | I've taken to simply wrapping everything sent to agents with a (try (catch Throwable ...)), just to avoid having to deal with agent errors. :-( |
| 11:06 | rhickey | cemerick: you want to ignore the errors? |
| 11:06 | chouser | either ignore or ...dum da dum... provide a callback. |
| 11:06 | chouser | cemerick: right? |
| 11:07 | cemerick | rhickey: well, that (catch Throwable) is in a quickie macro. The "real" code being sent has proper error handling. I just wanted a safety in the event of a stack overflow, OOME, etc. |
| 11:08 | cemerick | I'm only using agents in one spot, so it's entirely possible that I'm Doing It Wrong. |
| 11:09 | cemerick | The client code only really cares about two states, :error and everything else. When the former happens, it gets logged to be pondered later, very little that can be done in-place. |
| 11:09 | cemerick | Exceptions hanging around in the agent just muck up the other 99% of the work that goes off without a hitch. |
| 11:10 | rhickey | cemerick: so that ties into the auto-clear concept - send to callback and don't log internally |
| 11:10 | rhickey | I'm not opposed |
| 11:11 | cemerick | rhickey: I'm afraid I'm not at all versed in the various proposals wafting around for agent errors. Learn from me at your peril. ;-) |
| 11:11 | rhickey | I guess we had talked about the return value of the callback controlling that and the next agent state |
| 11:11 | rhickey | cemerick: these are things we already talked about |
| 11:11 | chouser | ok, so queued actions will proceed even if there's an error in the list. That's not a behavior I've taken advantage of. |
| 11:13 | chouser | so perhaps you might send several actions, some of which you know might fail and queue up a clear at the end of them so that future sends will be allowed. |
| 11:13 | rhickey | chouser: that's somewhat broken |
| 11:13 | chouser | sounds like a risky design, I suppose |
| 11:13 | chouser | yeah |
| 11:21 | tmountain | I was playing around with writing a squeeze function this morning to replace redundant runs of a given character in a string with a single instance of that character |
| 11:21 | tmountain | http://travis-whitton.blogspot.com/2009/11/squeezing-string.html |
| 11:22 | tmountain | for some reason, the version I wrote which uses reduce has terrible performance compared to using re-gsub from str-utils |
| 11:22 | tmountain | I'm wondering if it's something in my code or if I should avoid using reduce if I'm concerned about performance? |
| 11:23 | rhickey | tmountain: building strings by successive concatenation is a bad idea in every programming language, here too |
| 11:24 | leafw | tmountain: use str, which uses an StringBuilder. |
| 11:24 | rhickey | setting aside that regex will build a little machine for you, you'll need something with efficient append - streams, transient vector etc |
| 11:25 | rhickey | leafw: calling str over and over is no different than concat |
| 11:25 | leafw | true, still lots of new String being created. |
| 11:25 | tmountain | rhickey: so in the real world, I'd be better off with the regex or using something like a transient? |
| 11:26 | rhickey | tmountain: you can try a vector instead with little change to your existing code, and transient will little change to that |
| 11:26 | leafw | tmountain: no, rhickey meant you'd use a vector to accumulate strings, then apply str to it |
| 11:26 | tmountain | leafw: ok, gotcha |
| 11:28 | rhickey | make x a [] and (conj x y) |
| 11:29 | rhickey | str when done |
| 11:29 | rhickey | it still won't compete with a regex |
| 11:30 | rhickey | also, last is dangerous |
| 11:30 | rhickey | ,(doc last) |
| 11:30 | clojurebot | "([coll]); Return the last item in coll, in linear time" |
| 11:30 | rhickey | linear time == do not use for not known small |
| 11:31 | tmountain | rhickey: good to know. thanks for the tips. |
| 11:37 | replaca_ | p |
| 11:41 | replaca_ | oops |
| 11:46 | Chousuke | hm, there's a ninja commit in the git repo :P |
| 11:46 | Chousuke | "Author: unknown <Ninja@.(none)>" |
| 11:46 | chouser | yikes |
| 11:47 | Chousuke | probably someone with misconfigured tortoisegit :) |
| 11:47 | magnet | that's what he wants you to believe |
| 11:48 | chouser | ah, pretty to see whose it actually is. |
| 11:52 | chouser | seems to me that most of the time if you provide an error-fn for an agent you don't want the error queued for you or the value of the agent to change, so simply providing an error-fn could do that |
| 11:53 | chouser | you can always have your error-fn queue the error somewhere else if that's what you want, otherwise just don't provide an error-fn and let it be queued in the agent |
| 11:54 | SergeyDidenko | Hi! Can anyone help me to simplify the following code: (def mymap {:vec [1 2 3]}) |
| 11:54 | SergeyDidenko | (assoc-in mymap [:vec] (conj (:vec mymap) 5)) |
| 11:54 | SergeyDidenko | I mean the second line |
| 11:54 | SergeyDidenko | :) |
| 11:54 | chouser | so that really just leaves the (I think unusual) case where you want the error-fn to adjust the value of the agent, perhaps based on the fn, args, or old state of the agent. Could use the return value of error-fn to communicate that, but doing so complicates the "normal" case of just leaving it alone. |
| 11:55 | chouser | SergeyDidenko: (update-in mymap [:vec] conj 5) |
| 11:56 | SergeyDidenko | Thanks, chouser. Somehow missed that. |
| 11:56 | chouser | rhickey: how does a set-agent-value that only works inside error-fn strike you? |
| 11:57 | chouser | SergeyDidenko: np |
| 12:03 | chouser | having an error cause a change to the agent value isn't even an option today, so maybe that feature's just not needed. |
| 12:09 | chouser | so that would mean agents with an error-fn would never be in an 'error' state. If all the useful data (exception, agent, fn, args) get passed to error-fn as a map, you could do something as simple as (agent state :error-fn prn) to get an agent that never gets "stuck" and prints errors to stdout |
| 12:09 | chouser | I think I like that |
| 12:09 | chouser | rhickey: I'm not going to touch this without some sense I'm headed in the right direction. Do you want me to write this up better and maybe post to clojure-dev? |
| 12:15 | tmountain | I re-wrote the squeeze function, built up the data, and then applied str at the end, and it runs 27X faster ;-) http://travis-whitton.blogspot.com/2009/11/squeezing-string.html |
| 12:23 | chouser | (agent init :error-fn #(.printStackTrace (:error %))) if you want to get fancy |
| 12:26 | cemerick | chouser: nice :-) |
| 12:31 | djork | tmountain: nice |
| 12:31 | djork | tmountain: good call on leaving str to the last step |
| 12:43 | esj | anybody here interacted with COM in clojure ? |
| 12:45 | duncanm | esj: via Java, or via .NET? |
| 12:45 | devlinsf | esj: No, but there is the JaCOB library |
| 12:45 | esj | Java |
| 12:45 | devlinsf | esj: http://danadler.com/jacob/ |
| 12:46 | esj | yeah, i've seen JaCOB, com4j and ez jcom |
| 12:46 | esj | was wondering if anybody had opinions |
| 12:47 | duncanm | heh, i wonder if you can run Clojure on the MS JVM |
| 12:47 | duncanm | does clojure require java 5+? |
| 12:49 | devlinsf | duncanm: Yes, I believe java 5 is required |
| 12:50 | jweiss | can I use isa? with an interface? ie, how do i call isa? to check that Exception is a Throwable. |
| 12:51 | jweiss | sorry that (Exception.) is a Throwable. |
| 12:51 | devlinsf | ,(isa? (class {}) clojure.lang.IFn) |
| 12:51 | clojurebot | true |
| 12:52 | jweiss | ,(isa? (Exception.) java.lang.Throwable) |
| 12:52 | clojurebot | false |
| 12:52 | devlinsf | ,(isa? java.lang.Exception java.lang.Throwable) |
| 12:52 | clojurebot | true |
| 12:52 | jweiss | devlinsf: that's because they are both classes |
| 12:52 | devlinsf | jweiss: Try this |
| 12:52 | hiredman | ,(doc instance?) |
| 12:52 | clojurebot | "([c x]); Evaluates x and tests if it is an instance of the class c. Returns true or false" |
| 12:53 | Chousuke | tmountain: I wrote a quick version of that using a transient vector and it's about 30% faster it seems :) |
| 12:53 | devlinsf | ,(isa? (class (Exception.)) java.lang.Throwable) |
| 12:53 | clojurebot | true |
| 12:53 | hiredman | ,(instance? Callable #()) |
| 12:53 | clojurebot | true |
| 12:53 | hiredman | ,(instance? clojure.lang.IFn #()) |
| 12:53 | clojurebot | true |
| 12:53 | jweiss | hiredman: i ask about isa? because i'm using multimethods, which calls isa? |
| 12:53 | devlinsf | jweiss: Use the class fn |
| 12:54 | Chousuke | tmountain: http://gist.github.com/242063 |
| 12:54 | jweiss | so if i want to dispatch on a Throwable, how do i do that. |
| 12:56 | Chousuke | I like how few changes I had to make to use transients :P |
| 12:56 | jweiss | maybe i'm confused about what isa does. if i pass it two class objects, does it actually look at the hierarchy of their inheritance, or does it just say "yep, they're both class objects" |
| 12:56 | hiredman | it looks at the hierarchy |
| 12:56 | krumholt__ | can someone explain to me why (map (fn [a b c] (a b c)) '(list list) [1 1] [2 2]) => (2 2) i would expect ((1 2)(1 2)) |
| 12:56 | jweiss | hiredman: ok thanks |
| 12:57 | hiredman | you can even pass your own hierarchy to isa? |
| 12:57 | jweiss | hiredman: yeah i know, but i don't want to make my own in this case |
| 12:57 | Chousuke | krumholt__: you're using the symbol list as a function instead of the function list |
| 12:57 | Chousuke | ,('list 1 2) |
| 12:57 | clojurebot | 2 |
| 12:57 | krumholt__ | Chousuke, oh thanks |
| 12:58 | Chousuke | in general, it's ('sym coll not-found) |
| 12:58 | krumholt__ | what does a symbol used as a function do? |
| 12:58 | Chousuke | looks itself up in whatever |
| 12:58 | Chousuke | or returns the second argument if it fails. |
| 12:58 | krumholt__ | ok thanks |
| 12:58 | Chousuke | ie. same as a keyword. |
| 12:59 | Chousuke | you'd get the result you wanted if you used a vector instead of a quoted list :) |
| 13:00 | krumholt__ | very nice :) |
| 13:04 | devlinsf | krumholt__: to empasize chosuke's point |
| 13:04 | devlinsf | ,(map (fn [a b c d] (a b c d)) '(list list) [1 1] [2 2] [3 3]) |
| 13:04 | clojurebot | java.lang.IllegalArgumentException: Wrong number of args passed to: Symbol |
| 13:04 | devlinsf | ,(map (fn [a b c d] (a b c d)) [list list] [1 1] [2 2] [3 3]) |
| 13:04 | clojurebot | ((1 2 3) (1 2 3)) |
| 13:05 | tmountain | Chousuke: very cool |
| 13:06 | hiredman | ,(map (fn [a b c d] (a b c d)) (list list list) [1 1] [2 2] [3 3]) |
| 13:06 | clojurebot | ((1 2 3) (1 2 3)) |
| 13:06 | Chousuke | hiredman: very clever :P |
| 13:06 | hiredman | buffalo buffalo buffalo buffalo |
| 13:06 | defn | buffalo |
| 13:06 | duncanm | hmm |
| 13:06 | duncanm | how does that work? |
| 13:06 | Chousuke | duncanm: (list list list) creates a list of two functions, list and list |
| 13:07 | hiredman | ,(list list list) |
| 13:07 | clojurebot | (#< clojure.lang.PersistentList$1@bd11b1> #< clojure.lang.PersistentList$1@bd11b1>) |
| 13:07 | duncanm | ohh |
| 13:07 | defn | ,(list list list list) |
| 13:07 | clojurebot | (#< clojure.lang.PersistentList$1@bd11b1> #< clojure.lang.PersistentList$1@bd11b1> #< clojure.lang.PersistentList$1@bd11b1>) |
| 13:08 | defn | ,(list (list (list list list))) |
| 13:08 | clojurebot | (((#< clojure.lang.PersistentList$1@bd11b1> #< clojure.lang.PersistentList$1@bd11b1>))) |
| 13:08 | Chousuke | Hm |
| 13:08 | Chousuke | I think Lisps problem wasn't that there were too many parentheses |
| 13:09 | Chousuke | it was that there were too many lists. |
| 13:09 | Chousuke | :P |
| 13:09 | defn | heh |
| 13:09 | Chousuke | also, Lisp's |
| 13:10 | duncanm | headius: the talks from JRubyConf will be posted, right? do you have an estimate? |
| 13:11 | defn | i wish they'd hurry up and post the RubyConf S. Halloway talk |
| 13:12 | headius | duncanm: I do not know, but it will hopefully come quickly |
| 13:12 | headius | clojure came up several times...seems like a lot of people like the idea of jruby front-end with clojure for concurrent services in the back-end |
| 13:12 | headius | jruby's becoming a pretty nice web gluey front-end for other jvm langs |
| 13:17 | ambient | why can't there be one lang uber alles? :( |
| 13:18 | ambient | sql, java, xml, http, html, orm, templates, blah, it all gives me a headache. |
| 13:18 | headius | ambient: there will never be one lang |
| 13:18 | ambient | i see no reason why everything could not be done with lisp |
| 13:18 | ambient | or a language without any syntax |
| 13:18 | annealer | i see no reason why i'd want to program in a world like that |
| 13:18 | rhickey | chouser: I think you can't pass fn + args, since fn isn't a great identity, so if you just pass error plus current state, it would be easy to return that state or some reset value. Setting a handler can replace putting in internal error log afaic |
| 13:18 | annealer | variety is fun. there is no one language to rule them all |
| 13:19 | headius | because not everyone will want to use lisp, and so everyone using lisp will have to duplicate effort others have already put in |
| 13:19 | ambient | variety distorts focus, focus is good for getting things done |
| 13:19 | headius | better to reuse than reimplement again and again |
| 13:20 | annealer | variety breeds innovation. there's more to life than just getting things done |
| 13:21 | ambient | i guess it's a good thing, we wouldn't want computing to be too simple so that there are more jobs available |
| 13:21 | cemerick | headius: I had an old RoR hand chat me up over the weekend about how we should use JRoR as our eventual front end. He made a compelling case. |
| 13:21 | headius | who was that? |
| 13:21 | headius | cemerick: ^^ |
| 13:22 | headius | Rails 3 is also going to be even more compelling, since it will make it easier for us to swap bits out for existing java libs |
| 13:22 | cemerick | just a friend of mine who was deep into rails for some years, until he got yanked out into php land a few months ago |
| 13:22 | headius | there's several folks doing exactly that |
| 13:22 | headius | JRoR front plus Clojure in the back |
| 13:22 | headius | it's like a reverse mullet |
| 13:23 | ambient | does jruby hide the classpath awkwardness? |
| 13:23 | headius | generally, yes |
| 13:23 | headius | require 'java'; $CLASSPATH << 'whatever.jar' |
| 13:23 | cemerick | insofar as the web stuff is fundamentally "just a cost" for us (modulo the whole notion of quality UX), using something that designers and other like-minded folk are super-comfortable with makes sense. |
| 13:23 | headius | it's not flawless, but it works for most people just fine |
| 13:23 | defn | http://disclojure.org/ |
| 13:24 | chouser | I have exactly one rails project. It makes me unhappy. |
| 13:24 | ambient | the fact that you have only one or the fact that you have a rails project? |
| 13:24 | chouser | It's not ruby's fault either. |
| 13:25 | headius | we need to get a clojure-inline added to the inlining gem |
| 13:25 | cemerick | Just about any front-end I've ever had to build has been a miserable experience. |
| 13:25 | headius | someone added scala over the weekend |
| 13:25 | chouser | ambient: heh. I've used the project to learn rails, and I haven't been fond of what I've learned. |
| 13:25 | ambient | chouser: not meant as a joke, i was just wanting to know your opinion and your statement was ambiguous ;) |
| 13:25 | cemerick | chouser: I think the objective in general is, bang it out, it's all going to get replaced in 6 weeks. ;-) |
| 13:26 | defn | so true |
| 13:26 | cemerick | That was the general approach in the django world when I passed through there a while back, too. |
| 13:26 | chouser | I knew ruby already -- still my favorite pre-clojure language. |
| 13:26 | ambient | i've done some django, never touched rails |
| 13:26 | headius | rails 3 cleans up a lot of the yuck in rails |
| 13:26 | defn | I haven't tried rails 3 |
| 13:27 | chouser | I thought that since I hadn't done much standard server-side web app design that I should use a project that had made a bunch of design decicions already |
| 13:27 | bitbckt | defn: it's still "edge" |
| 13:27 | headius | there's at least one place going live with jruby + rails 3 soon |
| 13:27 | cemerick | headius: what's your pitch, then? Why should I use JRoR instead of something like compojure + enlive? |
| 13:27 | defn | i tried doing a HAML + SASS + RoR project with 2.x, but I do NOT recommend it |
| 13:27 | headius | they're kind of crazy though |
| 13:27 | headius | cemerick: no other web framework does as much for you as ror |
| 13:27 | defn | ^ |
| 13:27 | defn | there's a reason compojure is modeled after rails |
| 13:28 | ambient | most web frameworks give me headaches. I did Java Server Faces when it was barely version 1.0 |
| 13:28 | cemerick | headius: but aren't I risking a significant skills/attention dilution by having yet another language floating around? |
| 13:28 | headius | ambient: I think that's a feature of JSF, actually |
| 13:28 | ambient | headius: not just headaches, but uncontrolled bursts of blind rage |
| 13:28 | headius | cemerick: well, given that there's lots of folks building rails apps without really knowing ruby, I'd say the watering-down potential is low |
| 13:28 | KirinDave | cemerick: For the libraries. :) For the language, it's a lot like human language. Your total capacity grows with your total inventory. |
| 13:29 | headius | rails is really just a nice internal DSL for web apps |
| 13:29 | headius | the fact that it's in ruby is peripheral |
| 13:29 | defn | cemerick: i don't think so. You have CSS, XHTML, why not throw a couple more in for other specific aspects of your application? |
| 13:29 | chouser | I would argue with "nice", esp. around activerecord |
| 13:29 | KirinDave | Also, find something that is more suitable for rapidly developing a web app with a small team. |
| 13:29 | defn | chouser: no one is forcing you to use activerecord |
| 13:29 | KirinDave | Most people don't understand the tradeoffs Rails decided to make. |
| 13:30 | cemerick | defn: yeah -- I'm, uh, promiscuous w.r.t. programming languages already. Just trying to draw headius out a bit :-) |
| 13:30 | defn | hehe :) |
| 13:30 | headius | I'm not a great person to advocate rails over X though |
| 13:30 | headius | I don't do apps much these days |
| 13:30 | cemerick | chouser: I'd agree, but when one isn't using an RDBMS, then activerecord ceases to be a problem :-) |
| 13:30 | cemerick | heh, I should head over to #ruby and see what I can stir up. |
| 13:30 | icey | twitter has turned into a really good irc warning system. when you start seeing the OHs you know it's time to login :D |
| 13:30 | bitbckt | cemerick: #ruby-lang |
| 13:31 | bitbckt | But if you go too far toward Rails, you risk getting punted into #ror, from there. |
| 13:31 | cemerick | huh, and there's a #jruby too |
| 13:31 | KirinDave | Which is totally worthless. |
| 13:31 | bitbckt | Rightly so, imho. |
| 13:31 | KirinDave | jruby is much better. |
| 13:32 | KirinDave | This is an example of #ruby-lang |
| 13:32 | KirinDave | http://kirindave.tumblr.com/post/24570389/incredibly-stupid-people-on-freenode-ruby |
| 13:32 | KirinDave | I would avoid them. |
| 13:32 | cemerick | headius: is glassfish still the preferred container for JRoR? |
| 13:32 | bitbckt | +1 on glassfish |
| 13:32 | technomancy | bitbckt: did I meet you at JRubyConf? |
| 13:32 | headius | cemerick: it's very nice |
| 13:32 | bitbckt | technomancy: Yessir, you did. |
| 13:32 | headius | as app server or as gem |
| 13:32 | defn | OooOooo! http://orgmode.org/worg/org-contrib/babel/org-babel.php There is no clojure support for org-babel |
| 13:32 | bitbckt | technomancy: I'm the awkward idiot that bugged you before your talk. :-) |
| 13:32 | defn | err rather org-babel support for clojure |
| 13:32 | defn | now* |
| 13:32 | headius | bitbckt: who are you irl? |
| 13:33 | bitbckt | headius: Brandon Mitchell |
| 13:33 | cemerick | headius: is GF the only viable option, though? |
| 13:33 | headius | ahh ok, one more connection made then |
| 13:33 | technomancy | bitbckt: heh; yeah I was just kind of heads-down since I decided to to the lightning talk on short notice. |
| 13:33 | bitbckt | headius: We had dinner together a RubyConf 2 years ago. |
| 13:33 | headius | cemerick: nah, jror can deploy as a war file to lots of stuff |
| 13:33 | headius | GF just has some other nice non-WAR options |
| 13:34 | bitbckt | technomancy: I understand. I appreciated your advocacy. |
| 13:34 | bitbckt | And Halloway, of course. |
| 13:34 | technomancy | he sure knows how to pitch |
| 13:35 | bitbckt | Yes, he does. Despite Susser. |
| 13:35 | bitbckt | >_> |
| 13:36 | headius | is phil hagelberg on irc? |
| 13:37 | headius | he did a lightning talk at jrubyconf about using refs+stm from jruby |
| 13:37 | bitbckt | headius: technomancy |
| 13:37 | headius | oh, great :) hi, technomancy |
| 13:37 | bitbckt | hehe |
| 13:37 | headius | technomancy: I was thinking of ways to make that more seamless |
| 13:37 | bitbckt | Huzzah for Rubyists in #clojure... |
| 13:37 | KirinDave | headius: I am surprised you two haven't met. |
| 13:37 | KirinDave | Seems like you're on a collision course. |
| 13:37 | headius | I just didn't know nickname |
| 13:38 | headius | technomancy: I've also had a handful of people that want to implement a "clojure mode" in Duby that uses clojure refs |
| 13:38 | headius | perhaps for object fields or something |
| 13:38 | technomancy | that would be slick |
| 13:39 | bitbckt | Ooh. |
| 13:39 | technomancy | right now the problem with jruby integration is exception wrapping; retry exceptions inside ruby blocks get wrapped with ruby exceptions |
| 13:39 | chouser | icey: what do you meant? |
| 13:39 | technomancy | I was trying to patch Clojure to catch them at the appropriate place and retry, but I wasn't sure how to do that without making Clojure depend on JRuby |
| 13:39 | headius | yeah there's a backward-compat issue that's hard to deal with |
| 13:40 | jweiss | technomancy: i'm following step3 of swank-clojure install ( 3. |
| 13:40 | jweiss | if you want to use a newer version of Clojure than 1.0 you will need to build it yourself and symlink the compiled jar to ~/.swank-clojure/clojure-$VERSION.jar after removing the old version.) i am getting classnotfound on clojure.main. did i need to make the link names exactly the same as the old filenames, even though it's a different ver of clojure? |
| 13:40 | headius | i.e. previous jruby folks decided to wrap all incoming java exceptions in our NativeException, rather than just make Java exceptions get JI-wrapped and use that |
| 13:40 | duncanm | headius: i had a similar thought the other day - duby syntax + clojure semantics might be useful for those afraid of the lisp syntax |
| 13:40 | technomancy | jweiss: it should just use all the .jar files in ~/.swank-clojure if you don't set the classpath yourself. |
| 13:40 | headius | duncanm: to be sure, and probably not hard to wire in |
| 13:40 | headius | could spike a "clojure_compiler" for duby that does it without much effort |
| 13:41 | jweiss | technomancy: hm. do i need to recompile swank-clojure or anything like that? |
| 13:41 | technomancy | headius: yeah, tom was telling me that was the Way of the Future. |
| 13:41 | headius | technomancy: I think I just had an idea how to get real exceptions to propagate without breaking anything |
| 13:41 | headius | we'll just have NativeException#=== return true for Java exceptions |
| 13:41 | KirinDave | technomancy: I have a question for you. |
| 13:41 | the-kenny | technomancy: Would it be possible to bring swank-clojure-project to use the var swank-clojure-extra-classpaths in addition to the classpaths from the project? |
| 13:41 | jweiss | i just renamed the old jar files, appending ".old" and symlinked the new ones (freshly built from master git branch) |
| 13:41 | headius | then existing rescue blocks will still work |
| 13:41 | headius | hmmm |
| 13:41 | KirinDave | technomancy: I'm really curious about hacking on your build project now that i've spent so much time with it. But... I was curious... |
| 13:42 | KirinDave | technomancy: Would you be opposed to more direct interaction with clojars during the project invocation? |
| 13:42 | technomancy | headius: wow, if that would work, that'd be much cleaner. |
| 13:42 | KirinDave | technomancy: E.g., "I think it was... compjure or something. Let's search." |
| 13:43 | technomancy | the-kenny: there's an alias set up that is supposed to do that already |
| 13:43 | icey | chouser: sometimes I'll see someone mention a quote on twitter (invariably it's someone quoting headius) and it lets me know there's probably an interesting irc conversation going on ;) |
| 13:43 | headius | technomancy: yeah, definitely...then we'd just propagate the actual exception throughout |
| 13:43 | the-kenny | technomancy: Huh? my repl depends somehow on swank-clojure-extra-classpaths, and it doesn't work if I use swank-clojure-project |
| 13:44 | chouser | icey: ah, I see. thanks! |
| 13:44 | technomancy | the-kenny: nm; misread you. the idea of swank-clojure-project is that everything is self-contained; if you want to use jars outside the project dir use symlinks |
| 13:44 | the-kenny | technomancy: hm.. ok. |
| 13:45 | icey | chouser: are you chouser on twitter? |
| 13:45 | chouser | icey: no, chrishouser |
| 13:45 | technomancy | KirinDave: not sure quite what you mean... which leiningen task(s) would get hooked up to clojars? |
| 13:45 | KirinDave | technomancy: Well, a more fancy "new" would be pretty awesome, in my opinion. |
| 13:46 | headius | another possible reason to use ror for the front-end is that webapps are messy, stateful, mutable affairs; better to just let rails handle all that mess |
| 13:46 | technomancy | KirinDave: oh, so something that can pick from a number of new project templates? |
| 13:46 | technomancy | that'd be nice |
| 13:46 | KirinDave | technomancy: Yes. And also maybe even integration with the clojars metadata. |
| 13:47 | the-kenny | technomancy: Another question: When do I have to (require 'swank-clojure-autoload) in my .emacs? I couldn't get it to work without copying some from the file to my .emacs. |
| 13:47 | KirinDave | Like let's say the project page is tied to a github, you could envision git enabled tasks to pull out submodles as necessary and properly configure the project to build them. |
| 13:47 | defn | What are chunked sequences? |
| 13:48 | KirinDave | defn: It's an optimisation |
| 13:48 | technomancy | the-kenny: that should be handled for you by an elpa install... if you're not using elpa it's more complicated. |
| 13:49 | KirinDave | defn: They basically compute the sequence in chunks to amortise the advancement cost over time. |
| 13:49 | defn | ooo cljdb! |
| 13:49 | defn | KirinDave: ah-ha -- thanks |
| 13:49 | the-kenny | technomancy: I don't want to use elpa... I like to have control about such things. |
| 13:49 | rhickey | chouser: did you see above: I think you can't pass fn + args, since fn isn't a great identity, so if you just pass error plus current state, it would be easy to return that state or some reset value. Setting a handler can replace putting in internal error log afaic |
| 13:49 | KirinDave | defn: rhickey tweeted the link yesterday: http://bit.ly/7pmDgE |
| 13:49 | defn | ahhh, thanks again |
| 13:50 | defn | back to work... |
| 13:50 | technomancy | KirinDave: right now projects can have dev dependencies on leiningen plugins, which would work for tighter integration for everything except new (since new runs without a project in place) |
| 13:50 | chouser | rhickey: yes I did thanks. |
| 13:50 | technomancy | but we're thinking about adding a user-level config file, so you could have leiningen plugins loaded across the board |
| 13:50 | chouser | rhickey: you think it's important to allow the error-fn to change the state of the agent? |
| 13:50 | headius | I wish we all had a common set of function interfaces across langs |
| 13:50 | technomancy | the-kenny: ok, but if you don't use the supported installer then you're on your own, sorry. |
| 13:50 | headius | sigh |
| 13:50 | the-kenny | technomancy: hm ok, no problem. |
| 13:50 | headius | technomancy: is there a bare "clojure" gem? |
| 13:50 | bitbckt | headius: That would ruin all the fun. |
| 13:50 | KirinDave | technomancy: Which is why the task would have to be built in. |
| 13:50 | the-kenny | It's working fine now. |
| 13:51 | KirinDave | technomancy: But after that, things like git assists would be easy to add. |
| 13:51 | rhickey | chouser: yes, but if handed the current state, should be no problem to simply return it |
| 13:51 | technomancy | headius: not without my wrapper afaik |
| 13:51 | cemerick | bitbckt: "bozo bit company" :-D |
| 13:51 | bitbckt | cemerick: *sigh* |
| 13:51 | chouser | rhickey: ok |
| 13:52 | bitbckt | cemerick: I can't express how true that is. |
| 13:52 | headius | technomancy: we should release one, so there's a basline gem people can depend on |
| 13:52 | cemerick | bitbckt: don't worry, the times, they are a'changin. |
| 13:52 | headius | or I need to get off my ass and wire maven support directly into rubygems |
| 13:52 | bitbckt | cemerick: I hope so. |
| 13:52 | headius | or just clean this up and make it handle dependencies well: http://github.com/jruby/maven_gem |
| 13:53 | headius | then you'd just gem install clojure-1.0 and it would fetch from maven |
| 13:58 | icey | Does anyone know if anybody is working on a Clojure web framework that uses templates instead of representing HTML in Clojure? |
| 13:59 | KirinDave | icey: You can easily use a template agency with compojure. |
| 13:59 | chouser | rhickey: changing state means running validators which may in turn cause errors. I guess errors thrown by error-fn directly or from validators can be put in the errors list? |
| 14:00 | icey | KirinDave: pardon my ignorance, but what is a template agency? |
| 14:00 | KirinDave | icey: I dunno why I wrote agency. I must have had a serious brainfart there. |
| 14:00 | KirinDave | ... I am worried now. |
| 14:00 | KirinDave | I meant library but I typed agency. :( |
| 14:01 | icey | KirinDave: haha okay thanks :D I hit google thinking I had been looking for the wrong thing. Any idea what sort of engines people are using w/ compojure? |
| 14:02 | KirinDave | There was one really cool one I saw in here yesterday but I seem to have lost the think. |
| 14:02 | KirinDave | Fuck |
| 14:02 | KirinDave | What the hell is wrong with me. I'm typing every word but the word I mean. Am I grandpa gummy now? |
| 14:03 | cemerick | icey: enlive is great concept, haven't used it in anything significant myself, though. |
| 14:03 | KirinDave | icey: I was meaning to try http://clj-me.blogspot.com/2009/01/enlive-yet-another-html-templating.html |
| 14:03 | cemerick | just about anything can be wired in, though |
| 14:03 | KirinDave | http://github.com/cgrand/enlive/blob/2a15c466048f7e0311243b3d7a669705bbcbe072/src/net/cgrand/enlive_html/example.html |
| 14:04 | icey | Hmmm, enlive looks interesting; I might check that out, thanks :D |
| 14:05 | KirinDave | Yeah, it looks like a really good way to interact with pages that have very rich javascript. |
| 14:05 | icey | KirinDave: You can blame your mental state on the upcoming holidays; that seems to work for me |
| 14:05 | KirinDave | You can put in "stock" crap that simply provides sample data for your scripts. |
| 14:05 | KirinDave | icey: I wish. I did just get married. I hear that once you get married you get dumber. Something about settling down to have kids. |
| 14:05 | icey | KirinDave: that matches my experience with getting married ;) |
| 14:06 | icey | I need HTML templates because I will often get completed sites sent to me that just need code added for the functionality, and I don't want to translate everything into Clojure to make it work |
| 14:06 | KirinDave | yeah |
| 14:06 | KirinDave | Well that whole sexpr-html is a very misguided idea when you're building whole pages. |
| 14:06 | KirinDave | It's nice for things like list items. |
| 14:06 | cemerick | I still don't understand the urge to use sexprs instead of HTML. |
| 14:07 | KirinDave | cemerick: It's because people hate and/or look down upon HTML. |
| 14:07 | cemerick | I'm hoping it's deeper than that -- trying to leverage the power of macros, etc. |
| 14:07 | icey | cemerick: I really like them when I'm doing one-off small applications and I just need a couple of forms, for example. I can see everything at once, and use functions for my patterns |
| 14:07 | cemerick | Seems like one's looking for a nail in that case, tho. |
| 14:08 | chouser | my co-workers were very happy when I provided a way to use JavaScript syntax to build DOM tree for subsequent insertion on the page. |
| 14:08 | KirinDave | Right |
| 14:08 | KirinDave | For snippets it makes total sense. |
| 14:08 | KirinDave | Like, I have strings and a list of strings could easily be a list in html. |
| 14:08 | KirinDave | Great. |
| 14:09 | KirinDave | But the minute you start trying to make more complex tags it falls apart |
| 14:09 | KirinDave | And is less readable and less robust than HTML |
| 14:09 | chouser | hmmm |
| 14:09 | cemerick | It might be because I used them so much, but I still like JSPs -- super-simple, gets out of your way, gets the job done. |
| 14:09 | cemerick | Avoid putting "real" code in there, of course. |
| 14:09 | icey | sexprs are also really nice if your application is composed, depending on prior user actions; I have a survey application that completely changes depending on what's been answered previously |
| 14:09 | chouser | Seems to me HTML was designed for marking up text. s-expr's (and json) are lousy for that. |
| 14:10 | cemerick | chouser: what do you think of the sexpr js templating lib that popped up a bit ago? |
| 14:10 | chouser | but if you're creating a dense tree of small nodes, html/xml gets annoying fast, while s-exprs, json, yaml, etc. do nicely |
| 14:12 | chouser | hm, seems I wrote about this once. |
| 14:12 | chouser | heh. old. http://n01se.net/chouser/blog/#blogsd |
| 14:14 | chouser | cemerick: link? |
| 14:17 | cemerick | chouser: yeah, not that I can find it again now. :-/ |
| 14:18 | cemerick | chouser: http://github.com/arohner/scriptjure/ |
| 14:18 | cemerick | OK, not *so* recent, but new to me. :-P |
| 14:18 | djork | is it just me or is the list of announced features for JVM 7 a bit... underwhelming |
| 14:19 | cemerick | huh, by our own arohner, even. I didn't even notice at first blush. |
| 14:20 | djork | wow, scriptjure sure highlights the similarities between JS/clojure |
| 14:20 | djork | it would be interesting to see a return-less version |
| 14:20 | djork | i.e. just automatically insert return in tail position |
| 14:21 | KirinDave | I wonder if Clojure is ever going to switch from its CL-style macro system to a more scheme-like MBE system. |
| 14:21 | KirinDave | It seems like MBE is more in line with the way clojure does method definitions. |
| 14:21 | the-kenny | MBE? |
| 14:21 | KirinDave | Macro By Example |
| 14:21 | KirinDave | Have you see the way PLT-Scheme does macros? |
| 14:22 | KirinDave | Very beautiful. |
| 14:22 | djork | hmm, I just got used to Clojure's macros |
| 14:22 | the-kenny | No I haven't, sorry. |
| 14:22 | djork | I never got my head around PLT's |
| 14:22 | KirinDave | http://docs.plt-scheme.org/guide/pattern-macros.html |
| 14:22 | djork | mostly because the docs are quite dense |
| 14:22 | KirinDave | djork: I dunno, PLT Scheme has some of the most approachable documentation anyone has ever had for a lisp. |
| 14:22 | djork | oh wow, that' snot bad |
| 14:22 | KirinDave | djork: Just read the guide, not the reference. |
| 14:22 | the-kenny | Maybe you can implement MBEs with clojure macros :D |
| 14:22 | djork | for some reason I remember struggling with it a while back |
| 14:22 | djork | ah yes |
| 14:22 | djork | it was the reference |
| 14:23 | KirinDave | What's so cool about it is that it automagically handles masking. |
| 14:23 | KirinDave | So you can just write macros without consideration for variable capture. |
| 14:24 | the-kenny | KirinDave: Clojure has auto-gensyms. |
| 14:24 | KirinDave | the-kenny: They're still explicit. |
| 14:24 | KirinDave | or so the docs suggested? |
| 14:25 | the-kenny | Yes, but it's easier than in CL :) |
| 14:25 | KirinDave | You need to decide when you want them |
| 14:25 | KirinDave | Oh sure. |
| 14:25 | KirinDave | And sometimes you need the raw dawg macro |
| 14:25 | KirinDave | I wonder if I could write an MBE library for clojure... |
| 14:25 | KirinDave | For 95% of all macros, MBE is superior, safer, and almost always clearer. |
| 14:25 | djork | go for it |
| 14:26 | the-kenny | KirinDave: Just try it :) |
| 14:26 | djork | I'm happy with defmacro so far |
| 14:26 | djork | but I'm new to macros in general |
| 14:26 | the-kenny | If it isn't possible with macros (which i doubt), you can also implement it right in the reader ;) |
| 14:27 | KirinDave | the-kenny: It's possible with macros. Although it's best to be integrated into the reader to handle the namespacing issues. |
| 14:27 | djork | the-kenny: I think the trick with implementing MBE as a macro is the scope consideration |
| 14:27 | technomancy | did #^bytes get added as a type hint specifier, or is that still being worked on? |
| 14:33 | cemerick | technomancy: I think it's in there, yeah |
| 14:33 | jweiss | anyone here used c.c.logging ? getting it to work at the repl seems to be nontrivial |
| 14:33 | chouser | cemerick: ah, for generating js from clojure, I misunderstood you. I haven't used it yet, but do have a project where it might fit. So no real opinion other than it seems like to be filling a real need. |
| 14:33 | cemerick | jweiss: it needs a little work -- it binds at compile time |
| 14:33 | twbray | ,*command-line-args* |
| 14:33 | clojurebot | nil |
| 14:37 | cgrand | technomancy: #^bytes exists |
| 14:37 | technomancy | cool |
| 14:38 | technomancy | it looks like you can type hint with classes that don't actually exist; that seems pretty strange |
| 14:38 | technomancy | no warnings or anything |
| 14:38 | chouser | also with strings! |
| 14:44 | twbray | Pardon my extreme stupidity... been working in the REPL for a while, trying to run a script through main, failing. If I say (ns clojure.main) (defn main [args] ... ) in my script, then say java yadda yadda clojure.main my-script.clj, shouldn't that do it? |
| 14:44 | twbray | Looking at http://clojure.org/repl_and_main |
| 14:46 | chouser | twbray: when called from the command line like that, it's just executing everything at the top level. you could add your own (apply main *command-line-args*) to the bottom of the file if you want. |
| 14:47 | chouser | I think there's another way to get a fn named 'main' called, but I don't remember how. |
| 14:47 | twbray | All I really want is to get access to cmd-line args, having trouble getting *command-line-args* to have any values |
| 14:47 | technomancy | -main is for building an executable jar |
| 14:48 | twbray | There has got to be a way to get a command-line arg into my clojure script :( |
| 14:50 | lisppaste8 | Chouser pasted "command-line-args, simplest example" at http://paste.lisp.org/display/91038 |
| 14:52 | twbray | chouser: Thanks. That was my first attempt, must have had some subtle typo. |
| 14:59 | drewr | will clojure automatically benefit from Java 7's number underscores? |
| 15:00 | cemerick | isn't that just compiler sugar? |
| 15:01 | chouser | drewr: I doubt it. cemerick: probably |
| 15:01 | chouser | there have been proposals for spacers in numbers for Clojure |
| 15:01 | drewr | I remember those discussions |
| 15:01 | fogus_ | What was the final verdict? |
| 15:01 | cemerick | I don't see the appeal, but whatever |
| 15:01 | drewr | maybe this will help make a decision |
| 15:02 | devlinsf | Java 7 is dead. Isn't that why we're here? |
| 15:02 | chouser | :-( |
| 15:02 | drewr | I think (range 10_000_000) is much nicer than (range 10000000) |
| 15:02 | chouser | I like (range 1e7) |
| 15:02 | drewr | yeah, I forget about that |
| 15:03 | chouser | but of course that doesn't help with 121121521111 or whatever |
| 15:03 | chouser | of which there are so many in my code |
| 15:03 | the-kenny | I think 10_000_000 is very ugly |
| 15:03 | the-kenny | ,(identity 10,00) |
| 15:03 | clojurebot | java.lang.IllegalArgumentException: Wrong number of args passed to: core$identity |
| 15:03 | chouser | comma is whitespace! |
| 15:03 | drewr | comma is whitespace, not null space |
| 15:03 | chouser | ~comma |
| 15:03 | clojurebot | It's greek to me. |
| 15:03 | fogus_ | I like (range 046113200) |
| 15:04 | the-kenny | okay |
| 15:04 | chouser | fogus_: noooo... |
| 15:04 | duncanm | technomancy: is your site down? i'm having trouble installing SLIME from ELPA |
| 15:04 | drewr | fogus_: :-) |
| 15:05 | fogus_ | chouser: You made the point though... it's not often that you'll see those huge constants except in toy code |
| 15:05 | devlinsf | fogus_: I don't get it |
| 15:05 | fogus_ | ,(count (range 046113200)) |
| 15:05 | clojurebot | 10000000 |
| 15:06 | fogus_ | devlinsf: ^^^^^ |
| 15:06 | devlinsf | fogus_: Huh? Is it an overflow? |
| 15:06 | chouser | octal :-P |
| 15:06 | drewr | devlinsf: not base 10 |
| 15:07 | devlinsf | Oh, okay |
| 15:07 | devlinsf | ,(range 08000) |
| 15:07 | clojurebot | Invalid number: 08000 |
| 15:07 | chouser | read support for octal should look more like #octal:2342 |
| 15:07 | devlinsf | Got it |
| 15:07 | drewr | ,0xfff |
| 15:07 | clojurebot | 4095 |
| 15:08 | drewr | ,0777 |
| 15:08 | clojurebot | 511 |
| 15:08 | fogus_ | ,(range 010) |
| 15:08 | clojurebot | (0 1 2 3 4 5 6 7) |
| 15:09 | chouser | ,(+ 1 36rHello) |
| 15:09 | clojurebot | 29234653 |
| 15:09 | fogus_ | This is like modern day calculator curse words |
| 15:09 | chouser | heh |
| 15:10 | devlinsf | chouser: is there a shortcut for 2r1111 |
| 15:10 | chouser | shorter that "2r"? I don't think so |
| 15:10 | devlinsf | Well, something that implied binary |
| 15:11 | devlinsf | So it looks special |
| 15:11 | chouser | yeah, I don't think so. |
| 15:11 | devlinsf | Hmm, okay |
| 15:11 | devlinsf | Just the EE in me |
| 15:12 | chouser | Looking at the code now. The answer is "no" |
| 15:14 | chouser | but you can use a capital instead or r or x |
| 15:16 | fogus_ | Where does the zero-prefix for octal come from anyway? C? Fortran? |
| 15:16 | devlinsf | I'd guess C |
| 15:16 | chouser | C at least, if not before |
| 15:17 | fogus_ | I guess my question is what's the rationale? |
| 15:18 | chouser | rm, 8r377 is smalltalk |
| 15:18 | chouser | hrm |
| 15:18 | chouser | python3 uses 0o377 ...doesn't seem like a good idea to use ohs in numbers |
| 15:18 | alexyk | hi guys -- anyone used congomongo? |
| 15:19 | devlinsf | fogus: Wikipedia doesn't have anything :( |
| 15:19 | devlinsf | fogus_: Wikipedia doesn't have anything :( |
| 15:19 | fogus_ | Yeah, depending on your font, 0O010 could be a headache to look at in Python |
| 15:20 | fogus_ | devlinsf: Yeah, that's where I tried first |
| 15:20 | jasapp | alexyk: I use it a bit |
| 15:20 | devlinsf | Maybe the 0x is an seembly holdout? |
| 15:20 | devlinsf | *Maybe the 0x is an assembly holdout? |
| 15:21 | defn` | Easiest, simplest way to get a basic blog set up with clojure syntax highlighting? |
| 15:21 | defn` | Preferably something that I can just use out of the box without extra config. |
| 15:21 | fogus_ | defn`: Github? |
| 15:22 | defn` | fogus_: ? |
| 15:22 | the-kenny | defn`: gist.github.com |
| 15:22 | fogus_ | defn`: Like this http://github.com/raganwald/homoiconic |
| 15:22 | defn` | oh duh, i didn't think of that! |
| 15:22 | defn` | i was hoping to put it on my domain |
| 15:23 | defn` | but i could just redirect i guess |
| 15:23 | alexyk | jasapp: I'm saying (:use somnium.congomongo) and it can't find it, although the jar is on the path. |
| 15:23 | the-kenny | defn`: You can use github-pages :) If you're a premium member, you can set CNAME-Values too. |
| 15:23 | chouser | I think I've seen github gists embedded in blog pages |
| 15:24 | chouser | clojure.org uses a javascript thingy |
| 15:24 | fogus_ | I embed gists in my blog |
| 15:24 | technomancy | defn`: M-x htmlize-region is awesome if you blog from Emacs |
| 15:24 | chouser | fogus_: probably where I saw it then. :-) |
| 15:25 | duncanm | what's the difference between :use and :require again? |
| 15:25 | the-kenny | fogus_, chouser: http://github.com/blog/122-embedded-gists |
| 15:25 | fogus_ | defn`: I use this cool WP plugin that lets me wrap the code in a tag and if a gist doesn't already exist it creates one and links to that |
| 15:25 | Chousuke | embedded gists are not so nice. they require javascript and just *disappear* if you don't have it enabled :P |
| 15:26 | Chousuke | it's pretty confusing to read blog posts stating "here's the code" when there's nothing. |
| 15:26 | devlinsf | duncanm: use mixes all of the functions into the namespace. require imports them and lets you alias them |
| 15:27 | devlinsf | duncanm: require helps avoid collisions. see str-utils2 for an example of a lib that is better reuire'd than use'd |
| 15:27 | jasapp | alexyk: is that in the ns macro? |
| 15:27 | fogus_ | Chousuke: The plugin I use takes care of that... I wish I could remember the name without having to log into my blog admin :( |
| 15:27 | alexyk | yeah |
| 15:27 | alexyk | I'm using it outside the macro, can I? |
| 15:29 | jasapp | I'm not sure I understand exactly, but if it's outside the ns macro, you want use the function, not use the keyword. |
| 15:29 | defn` | fogus_: that is cool |
| 15:30 | fogus_ | defn`: I use this http://blog.kno.at/tools/highlight-source-pro/ |
| 15:30 | alexyk | jasapp: ah ok, am very new to clojure :) in ns works |
| 15:30 | jasapp | alexyk: and you'll also want somnium.congomongo to be quoted |
| 15:31 | alexyk | jasapp: single quote in front, right? |
| 15:31 | fogus_ | defn`: Whoops, that's not right. I use http://pomoti.com/gist-it |
| 15:32 | alexyk | fogus_: "Basically, that problem usually happens with those who ‘programming-bloggers’ are the main activity when not sleeping." :) |
| 15:35 | alexyk | what do people use for SQL? anything prettier than raw jdbc? |
| 15:36 | drewr | alexyk: for simple cases, c.c.sql suffices |
| 15:37 | chouser | I continue to be intruiged by http://www.gitorious.org/clojureql/ |
| 15:37 | chouser | haven't actually used it thought |
| 15:37 | chouser | though |
| 15:37 | chouser | I'm in nosql land now |
| 15:37 | drewr | chouser: +1 |
| 15:37 | drewr | cql is really good, I just haven't had time to write a mssql backend |
| 15:38 | alexyk | drewr: who cares about MS :) postgres is all I need |
| 15:39 | alexyk | chouser: I have an abstract system where I try different backends. Tried BDB and Mongo, but Postgres will do too. |
| 15:40 | chouser | if you're not writing sql-like queries in your app code, clojureql is probably the wrong level |
| 15:40 | fogus_ | chouser: Which nosql? |
| 15:40 | chouser | writing our own :-) |
| 15:40 | drewr | nice |
| 15:41 | fogus_ | NIH! ;-) |
| 15:41 | chouser | I was skeptical, but came around. I think we have sufficiently compelling reasons for not building on anything that's out there right now. |
| 15:41 | fogus_ | chouser: In clojure? |
| 15:42 | drewr | all the nosql tech is so young |
| 15:42 | drewr | I've been impressed with cassandra but it's not quite there yet for our needs |
| 15:42 | chouser | fogus_: clojure, C++, Java plus some jruby for testing, a custom query language, and no doubt eventually php bindings. |
| 15:45 | somnium | alexyk: I've used it :) |
| 15:46 | alexyk | somnium: works nicely! :) |
| 15:46 | alexyk | none of the ORM headaches from Scala... since not much types enforcement in here :) |
| 15:47 | rhickey | chouser: sorry, away for a bit - yes, if value returned by error-handler fails validation just put in normal error list |
| 15:47 | somnium | alexyk: yes, json format fits clojure's structures well. unfortunately I can't use it for my current project :( but I'm glad its useful to some people |
| 15:49 | alexyk | somnium: there's a competing project on github, by gilbertl, did you see that? |
| 15:49 | somnium | I'm not sure that we're competing :) We both use an open source language to wrap an open source driver for an open source database |
| 15:50 | alexyk | somnium: you are competing for users! :) |
| 15:50 | chouser | amazing amount of complexity packed in here. :-/ when to skip releasePendingSends()? |
| 15:51 | alexyk | ok, alternative... any idea of the differences? |
| 15:53 | chouser | skip releasePendingSends() even if the error was handled by an error-fn, right? |
| 15:54 | rhickey | hmmm |
| 15:54 | somnium | alexyk: I did look at it, I suspect its a bit slow, since it traverses maps with clojure.walk to handle keywords. Though I kind of cheated and wrote a little java class to do that. |
| 15:54 | duncanm | technomancy: i keep on seeing 'failed to download clojure jars' when i run M-x slime on a fresh machine |
| 15:54 | alexyk | somnium: you have a better readme, so I picked yours. :) |
| 15:54 | somnium | :) |
| 15:55 | chouser | if the action throws something, you'd be surprised to find some 'sends' go out but not others, wouldn't you? |
| 15:55 | alexyk | somnium: I have a 70 GB database with 100M twits, let's see how you can handle *that* :) |
| 15:56 | rhickey | chouser: which went out? |
| 15:56 | chouser | though if a watcher fails, you might be surprised if any sends are held back. |
| 15:56 | somnium | alexyk: it can create IPersistentMaps quickly, but I guess you'll run out of ram pretty quickly with that load :) |
| 15:56 | alexyk | somnium: is there any tuning I must/can do? I have a 64 GB RAM box for this job |
| 15:57 | chouser | if your action does: send 1, throw, send 2 ...1 will go out if released, but 2 would never have been queued |
| 15:57 | somnium | alexyk: mongo doesn't support concurrent reads until 1.4, + deftype and defprotocol make it even faster, so I'm kind of waiting for the next release |
| 15:57 | alexyk | 35 GB are data, 35 GB indexes |
| 15:57 | alexyk | somnium: you mean 1.1.4? |
| 15:57 | somnium | alexyk: yes 1.1.4 |
| 15:57 | alexyk | what are deftype and defprotocol? |
| 15:58 | somnium | alexyk: new performance enhancing clojure features, as for mongo, I guess you'll want to shard it, but the driver won't help with concurrency right now :( |
| 15:58 | kotarak | _ato: you are the clojars guy, right? |
| 15:59 | alexyk | somnium: java driver or clojure wrapper? |
| 16:00 | rhickey | chouser: ah, ok, so, never queued, not really missed. It seems there could be no correct default policy there, but currently we eat on error, so let's keep that. I guess a composite return could tell us what to do... |
| 16:01 | somnium | alexyk: well, the clojure wrapper is very threadsafe, but to get a performance boost from concurrency you'll need a connection pool to n databases |
| 16:01 | somnium | I would check the java driver to see if it offers any support for that |
| 16:01 | chouser | a composite return could also allow nil to mean no change to agent value, which would be handy for many minimal examples. |
| 16:01 | alexyk | somnium: ok |
| 16:02 | rhickey | chouser: how so? nil could be the new value |
| 16:03 | rhickey | I'm not sure I follow the problem with returning what you are handed |
| 16:03 | rhickey | do you want to avoid the validation etc? |
| 16:04 | chouser | No, it's not a big problem, but I expect a lot of simple cases to end up with error fns like #(do (prn %2) %1) instead of just prn |
| 16:04 | chouser | real-world code will have more complex handlers and returning an explicit new value won't feel awkward there |
| 16:05 | technomancy | kotarak: _ato is on aussie time IIRC, but I'm working on the project with him |
| 16:05 | chouser | but I thought you were suggesting error-fn return {:pending-sends :release, :new-value foo} or something, in which case nil could mean no change. |
| 16:05 | rhickey | yeah, I wouldn't worry, people will write one handler they like and reuse |
| 16:06 | chouser | ok |
| 16:06 | defn` | poor s_e_t_h and his failed clojure blog post |
| 16:06 | kotarak | technomancy: ah. Ok. Are there special requirements on the filenames copied? specifically: does the pom need to be called "pom.xml" or could it also by "foobar-1.2.0.pom.xml"? |
| 16:06 | rhickey | chouser: nil for the entire return? would that relase sends? |
| 16:07 | chouser | I ... uh, I dunno. I guess I would think not. |
| 16:07 | technomancy | kotarak: I don't see "pom.xml" hardcoded in, so I suspect your longer version would work. give it a try. |
| 16:08 | ordnungswidrig | clojure compiler error message is driving me nuts. the file with the namespace a.b must go in /a/b.clj right? |
| 16:08 | chouser | releasing sends seems like something you want only when things are working "normally" |
| 16:08 | kotarak | technomancy: ok, will try. |
| 16:08 | chouser | an action can always try/catch itself if it's expecting errors |
| 16:09 | ordnungswidrig | hmm, are dashes allowed in ns names? a-b.c-d ?? |
| 16:09 | chouser | ordnungswidrig: yes, but are _ in file and directory names |
| 16:09 | rhickey | chouser: yeah, until you think about the exception conveying enough info for the handler to fabricate a valid work step. The biggest problem is not knowing how far through any sends you've gotten, as you mentioned before |
| 16:09 | ordnungswidrig | chouser: thanks! |
| 16:10 | rhickey | really, any action that sends needs to have its own handler, even if it ends up rethrowing |
| 16:10 | chouser | how do erlang and scala do this? |
| 16:10 | rhickey | so, let's just not release, and have a single return of new state - you can do an identity test to avoid validation/watchers |
| 16:11 | rhickey | chouser: erlang is fail == die |
| 16:11 | chouser | oh |
| 16:11 | chouser | I assume neither hold "sends" at all? |
| 16:11 | rhickey | with death notification and restarts |
| 16:12 | chouser | we do notifyWatches on an action, even with the value is unchanged. You want to withhold notification if the error-fn makes no change? |
| 16:12 | rhickey | so you just have this chain of death notification links |
| 16:12 | ordnungswidrig | Anybody seen this with slime/swank: error in process filter: Symbol's function definition is void: swank-clojure-slime-mode-hook |
| 16:13 | chouser | also, is it really worth it to you to have me write this when all I do is pester you with every little decision. ;-) |
| 16:13 | rhickey | that has toggled back and forth a few times, note the boolean return on setState |
| 16:13 | ordnungswidrig | I'm using slime from elpa and maven swank-clojure 1.0-SNAPSHOT |
| 16:14 | chouser | rhickey: yeah, I noticed. |
| 16:14 | rhickey | I think it was your use case that swapped it last time :) |
| 16:15 | chouser | :-) |
| 16:15 | rhickey | a countdown watcher or something |
| 16:15 | technomancy | ordnungswidrig: did you install swank-clojure or just slime? |
| 16:16 | technomancy | (in elpa) |
| 16:16 | ordnungswidrig | both |
| 16:16 | rhickey | in some sense, a watcher is like a permanent pendingSend, so they should have the same policy |
| 16:16 | ordnungswidrig | I suppose elpa takes precedence on debians slime |
| 16:16 | chouser | except they happen synchronously. But yeah, I definitely see your point. |
| 16:17 | technomancy | never used debian's slime; they could be conflicting |
| 16:17 | hiredman | woa |
| 16:17 | hiredman | technomancy: you've seen javagems? |
| 16:17 | rhickey | so, no watchers on identical state |
| 16:17 | chouser | it seems a bit odd that an error-fn could change the state of an agent because a watcher threw something |
| 16:17 | ordnungswidrig | technomancy: I think it an outdated swank-clojure that maven is using. I try starting the repl by slime |
| 16:18 | rhickey | I'm happy having watcher errors go into the normal list |
| 16:18 | rhickey | really, a watcher that can throw is bogus |
| 16:18 | chouser | my main complaint about the normal list is how it poisons the agent |
| 16:18 | chouser | yes |
| 16:18 | rhickey | but, I'm sure people want to route all problems to a single place |
| 16:19 | chouser | but routing errors seems a bit different than fixing up an agent state |
| 16:19 | rhickey | or there could be a watcher-error-handler |
| 16:20 | ordnungswidrig | technomancy: strange. slime starts a clojure repl but swank-clojure-project fails on missing clojure libs |
| 16:21 | chouser | wather-error-handler return values would be ignored instead of updating the agent |
| 16:21 | rhickey | that's probably easier architecturally for us, and makes more sense = would be passed exception ony, ignored return |
| 16:21 | chouser | but could default to be the same as the normal error-fn? |
| 16:21 | rhickey | no |
| 16:21 | rhickey | different args |
| 16:22 | chouser | no state |
| 16:22 | rhickey | right |
| 16:23 | rhickey | in fact, if no watcher error handler provided - I'd prefer to ignore them |
| 16:23 | chouser | ok! |
| 16:23 | rhickey | couldn't ignore before because there would be no way to find out about the failures |
| 16:23 | ordnungswidrig | technomancy: got it. had to run mvn dependency:copy-dependencies first :-) |
| 16:24 | rhickey | now user choice |
| 16:24 | chouser | right |
| 16:24 | chouser | we can consider changing the default for action errors to match at some later point. :-) |
| 16:25 | rhickey | chouser: well, there might be user code already using agent-errors |
| 16:25 | chouser | right |
| 16:25 | chouser | breaking change. not for now. |
| 16:25 | rhickey | right |
| 16:25 | chouser | :error-handler is better than :error-callback |
| 16:25 | rhickey | yes |
| 16:25 | kotarak | technomancy: it works! the name is not interesting. clojuresque 1.1.0 pushed to clojars. :) (formerly known as clj-gradle) |
| 16:26 | duncanm | technomancy: sigh, am i doing something stupid? M-x slime isn't workign for me ;-P |
| 16:27 | chouser | setWatcherErrorHandler in ARef instead of Agent? |
| 16:27 | ordnungswidrig | duncanm: what's your error? |
| 16:27 | duncanm | ordnungswidrig: failed to download clojure jars |
| 16:28 | duncanm | oh doh |
| 16:28 | duncanm | now it's working |
| 16:28 | ordnungswidrig | duncanm: *g* |
| 16:28 | rhickey | chouser: yes, and IRef |
| 16:28 | rhickey | actually, no |
| 16:29 | rhickey | this is just an async problem |
| 16:29 | rhickey | all sync things can just let exceptions flow out |
| 16:29 | rhickey | so, on Agent only |
| 16:30 | chouser | yes, ok. |
| 16:32 | technomancy | hiredman: yeah... the authors emailed me. it's an interesting project, but I don't think it's that relevant to clojure. |
| 16:32 | chouser | validator throws: error-fn is called, pending sends are dropped. |
| 16:33 | rhickey | chouser: sounds right |
| 16:33 | chouser | but ... watchers are still triggered if error-fn changes the state. |
| 16:33 | krumholt__ | why does (eval (fn [] "test")) not yield "test" as a result? instead it returns what i would expect from (eval '(fn [] "test")). could someone explain that to me? |
| 16:35 | chouser | and sends queued by error-fns and by watchers triggered by error-fns are ... released? disallowed!? this all feels a bit wrong. |
| 16:35 | somnium | krumholt__: eval != invoke, try ((eval '(fn [] :foo))) |
| 16:36 | chouser | krumholt__: (fn ...) returns a value, a function. Eval'ing a value just returns the value. |
| 16:37 | chouser | krumholt__: or: (eval '((fn [] :foo))) |
| 16:37 | krumholt__ | oh ok thanks. a function is a value eval returns that value makes sense thanks |
| 16:37 | rhickey | chouser: let's break it down |
| 16:38 | rhickey | the reason to allow the handler to 'fix' the state is because re-queueing a new action will change the (possibly important) order |
| 16:38 | chouser | not sure what that means, but error-fn inserting a state change feels like the source of complexity to me |
| 16:38 | chouser | heh |
| 16:39 | rhickey | pending sends may be an incomplete set, there's no way to know, so if your action sends and might throw, you should have your own internal handling |
| 16:39 | chouser | ok, yes. There's no better way to indicate which sends you want to do than your own appropriately grouped try/catches |
| 16:40 | chouser | in the action |
| 16:40 | rhickey | so pending sends have to be chucked, but the one case you couldn't self-handle is validation failure |
| 16:41 | chouser | validators can't send because they're supposed to be pure |
| 16:41 | chouser | so no pending issue there |
| 16:41 | somnium | question to vimclojure users: is there a recommended way to manage the classpath for standard ./src ./lib ./build project structure? |
| 16:42 | kotarak | somnium: the launcher adheres to CLASSPATH env var, the new one also reads a .clojure file in the current directory. |
| 16:42 | chouser | does the same apply then to error-fn? can be a pure fn of the state and exception but shouldn't throw or send? |
| 16:43 | rhickey | validation failure is a programming error, so finding out about about it is most important |
| 16:43 | kotarak | somnium: you can also set CLOJURE_EXT to load jars in that directory |
| 16:43 | rhickey | error-fns aren't pure, in that they may frequently do queue I/O |
| 16:44 | rhickey | but people use agents as queues... |
| 16:44 | chouser | is an error-fixer different than an error-queuer? |
| 16:44 | rhickey | handler implies both |
| 16:44 | chouser | yes I know |
| 16:45 | chouser | I'm wondering if that's an bad conflation |
| 16:45 | ikitat | I'm at a loss how to make use of clojure.test/use-fixtures http://paste.pocoo.org/show/152745/ gives me "Unable to resolve symbol: x in this contex" |
| 16:46 | rhickey | I think if it is clear - "I fixed this" vs "it never happened", then other decisions become easier |
| 16:46 | hiredman | ikitat: I don't know anything about test-is |
| 16:46 | hiredman | but that looks like an issue of lexical v. dynamic scope |
| 16:46 | chouser | rhickey: ok, yes. |
| 16:47 | rhickey | I fixed it - all messages go out, it never happened - none do |
| 16:47 | chouser | yes |
| 16:47 | somnium | kotarak: where can I read on .clojure file in the current dir? I was thinking of writing a alternate bash script similar to swank-clojure-project (locate build.xml/pom.xml and build classpath). |
| 16:47 | hiredman | but then again, I don't know what I am talking about |
| 16:47 | somnium | kotarak: btw, mine breaks if I open a random .clj file not already in CLASSPATH, so maybe I have something configured wrong |
| 16:48 | rhickey | so, state identity is too weak |
| 16:48 | chouser | do, do you indicate which you're doing by returning an = value, or is that too much magic |
| 16:48 | chouser | yeah |
| 16:48 | rhickey | or at least unclear |
| 16:48 | kotarak | somnium: it's not a bug, it's a feature. You can turn it off in the latest bleeding-edge. |
| 16:48 | chouser | if you didn't fix it, you have no new value to provide |
| 16:49 | ikitat | hiredman, yeah, I figured that it's a scoping issue, the documentation for test-is isn't clear (to me) how this can be used |
| 16:49 | somnium | kotarak: I'm not qualified to have an opinion on bug/feature status at this point :) I'll try the bleeding edge, does it work with new branch? |
| 16:49 | chouser | I guess a single handler might need to look at the exception to know what it's doing, so providing separate fixer-fn from logger-fn is bad |
| 16:49 | rhickey | but as your use case indicated, sometimes a valid work step doesn't change the state |
| 16:49 | kotarak | somnium: yes, but the highlighting is not 100% up-to-date. |
| 16:50 | hiredman | ,(doc clojure.test/user-fixtures) |
| 16:50 | clojurebot | Gabh mo leithscéal? |
| 16:50 | kotarak | somnium: this will fix your problem: http://bitbucket.org/kotarak/vimclojure/changeset/f80ecd0532b7/ |
| 16:50 | rhickey | I think return the exception to indicate 'didn't happen', else state and all messages go |
| 16:50 | hiredman | ,(doc clojure.test/use-fixtures) |
| 16:50 | clojurebot | No entiendo |
| 16:50 | chouser | hm!! return the exception. |
| 16:51 | rhickey | acts as an implicit notFixed flag |
| 16:51 | chouser | just too unlikely that someone wants to store that particular exception in the agent? better than re-throwing it? |
| 16:51 | kotarak | somnium: ad parsing poms: I don't see this is as the responsibility of vc. The user has to setup his classpath with the ng-server. This can for example done via some target for maven, ant or gradle. |
| 16:51 | kotarak | somnium: parsing poms is a nightmare with vim. |
| 16:51 | rhickey | we don't want rethrow that's for sure, it's still handled |
| 16:51 | rhickey | just not fixed |
| 16:52 | chouser | treat that particular exception different from any other exception then? |
| 16:52 | rhickey | ? |
| 16:53 | chouser | if the error-fn returns an exception other than the one passed in, that becomes the new value of the agent. |
| 16:53 | kotarak | somnium: as for the .clojure, I must confess, that I haven't pushed the changeset, yet. sorry. My mistake. |
| 16:53 | rhickey | we could have a return-this-value-if-not-fixed, but seems a bit much |
| 16:53 | chouser | yes, I can see that. |
| 16:53 | hiredman | ikitat: it looks like a fixture is just a normal function |
| 16:53 | ikitat | the only usage of use-fixtures in clojure-contrib seems to modify *ns* and that is the one and only case I can find. |
| 16:53 | somnium | kotarak: ah ok, well I threw together an alternative nailgun launcher that just exports command line args to classpath, and that seemed to work |
| 16:53 | hiredman | so you will need to setup x as a dynamically rebound var |
| 16:53 | rhickey | the other option is the agent itself |
| 16:53 | chouser | heh |
| 16:54 | rhickey | but people get so confused already between the agent and its state |
| 16:54 | hiredman | ikitat: http://clojure.org/vars |
| 16:54 | chouser | I'm ok with the exception itself, esp. for an experimental feature |
| 16:54 | rhickey | what is getting passed - the agent or its state? |
| 16:55 | somnium | kotarak: oh, my idea wasn't to parse .pom, just find it, and then add ./src ./lib etc to classpath, then launch nailgun, for convenience |
| 16:56 | chouser | seems like if you've got an agent managing exceptions as values *and* your actions throw exceptions *and* you've got an error-fn *and* you want to fix up the error, well, you already used up all your grace. |
| 16:56 | chouser | rhickey: patch in assemble passes agent to error-fn, but I think that's wrong, should be state. |
| 16:57 | chouser | in assembla |
| 16:57 | rhickey | it's not exceptions as values, its the identical exception that was passed to the handler, not by type at all |
| 16:57 | chouser | yes |
| 16:57 | kotarak | somnium: ah. Ok. I just have CLASSPATH=src:classes CLOJURE_EXT=lib and I start the ng server from the project root. Universally working for all my projects. :) |
| 16:57 | rhickey | so unless the agent is going to use that specific exception object as its state... |
| 16:58 | chouser | right |
| 16:58 | chouser | loony |
| 16:58 | rhickey | chouser: this was a simpler idea when it was to be a queue |
| 16:58 | rhickey | no question about the activity of the handler itself |
| 16:59 | rhickey | for instance, we're still not good if the handler wants to send the fix as a new action |
| 16:59 | chouser | ok, and watchers aren't fired until after the error-fn, and only if error-fn doesn't return the sentinel |
| 17:00 | chouser | the handler can either send (if it wants it queue at the end) or do an action directly, can't it? |
| 17:00 | ikitat | hiredman: it seems the right thing to do is (def x) (def y) (use-fixtures :each ... (binding [x 2 y 3] ... ) I was hoping to have a way to not bleed x and y into the namespace |
| 17:00 | rhickey | chouser: a reentrant send? where does it go? |
| 17:01 | somnium | kotarak: ok, that is simpler. thanks |
| 17:01 | Anniepoo | hmm... ok, beginner question |
| 17:02 | chouser | if error-fn does a send and returns a fixed-up value, all the actions's queued sends and the error-fns sends all get released, don't they? |
| 17:02 | rhickey | it will be in pending sends, which aren't going out since not fixed |
| 17:02 | chouser | oh, you're saying if error-fn wants to send but not fix |
| 17:02 | chouser | bleh |
| 17:02 | rhickey | I guess it would have to know to return the existing state |
| 17:03 | rhickey | also, handed only the state, to whom does it send? |
| 17:10 | ordnungswidrig | I have lengthy call of ((-> f wrap1 wrap2 wrap3 wrap4) arg) where wrap* are higher order functions that wrap a given function. How can I trace invokations of the wrappers easily? |
| 17:12 | hiredman | (doto prn) |
| 17:12 | chouser | rhickey: *agent* since we're in-thread |
| 17:16 | ordnungswidrig | hiredman: say how? |
| 17:17 | rhickey | chouser: it seems like there are more facets - like would people still want to be able to neuter the agent for further actions? what about other things in its queue |
| 17:17 | hiredman | ordnungswidrig: or something like that |
| 17:18 | ordnungswidrig | *g* I'll try |
| 17:18 | hiredman | ((fn [x] #(doto (x) prn))) |
| 17:19 | hiredman | ,(-> p ((partial partial inc)) ((fn [x] #(doto (x) prn)))) |
| 17:19 | clojurebot | java.lang.Exception: Unable to resolve symbol: p in this context |
| 17:19 | hiredman | ,(-> 1 ((partial partial inc)) ((fn [x] #(doto (x) prn)))) |
| 17:19 | clojurebot | #<sandbox$eval__5995$fn__5997$fn__5999 sandbox$eval__5995$fn__5997$fn__5999@15fc68a> |
| 17:19 | hiredman | ,((-> 1 ((partial partial inc)) ((fn [x] #(doto (x) prn))))) |
| 17:19 | clojurebot | 2 |
| 17:19 | clojurebot | 2 |
| 17:20 | rhickey | also, if you 'fix' in order to send a true fixing action, other messages and the watchers will go out |
| 17:22 | michaeljaaka | hi, how to easily make passing parameters to function by symbols? |
| 17:22 | michaeljaaka | I have looked into core.clj |
| 17:22 | rhickey | in a queue model, there'd be no immediate fixing, and thus no sends at all, but we'd have to send the agent itself since dequeuing on another thread |
| 17:22 | ordnungswidrig | hiredman: thanks. |
| 17:23 | michaeljaaka | and found something like (defn me[ & args] (let [ x (apply hash-map args)] ... and later (:sym x) |
| 17:23 | michaeljaaka | is it ok? |
| 17:23 | michaeljaaka | or is there any easier way |
| 17:24 | michaeljaaka | btw. I was activly writing to clojure google group but my last two post didn't appear - am I banned there, spamming there or something? |
| 17:25 | hiredman | michaeljaaka: you can use straight up map destructuring |
| 17:25 | hiredman | ~destructuring |
| 17:25 | clojurebot | destructuring is http://clojure.org/special_forms#let |
| 17:27 | michaeljaaka | ok, I will try it again, last time when was trying to play with function parameters nothing worked for me ;( |
| 17:34 | michaeljaaka | "Clojure supports abstract structural binding, often called destructuring, in let binding lists, fn parameter lists," |
| 17:34 | michaeljaaka | (defn testfun[ & a :as e ] (println (:dom a))) |
| 17:35 | michaeljaaka | expressions given in example doesn't work for fn parameter lists |
| 17:35 | hiredman | michaeljaaka: then read the example again |
| 17:36 | michaeljaaka | ok :) (note: I understand examples for let binding) |
| 17:36 | djork | michaeljaaka: let/fn have the same destructuring rules |
| 17:37 | hiredman | michaeljaaka: you are missing en tire set of [] |
| 17:38 | hiredman | so obviously you did not read the example closely enough |
| 17:39 | michaeljaaka | hmmm it is obvious that for let |
| 17:39 | michaeljaaka | I have to pass second [] |
| 17:39 | djork | ,((fn [[a b & c :as d]] (println a b c d)) [:foo :bar: bat :baz]) |
| 17:39 | clojurebot | Invalid token: :bar: |
| 17:39 | michaeljaaka | which initializes left form |
| 17:39 | djork | oops hah |
| 17:39 | devlinsf | Hey, how do I create fields in a gen-class? |
| 17:39 | djork | ,((fn [[a b & c :as d]] (println a b c d)) [:foo :bar bat :baz]) |
| 17:39 | clojurebot | java.lang.Exception: Unable to resolve symbol: bat in this context |
| 17:39 | djork | I fail it |
| 17:39 | djork | ,((fn [[a b & c :as d]] (println a b c d)) [:foo :bar :bat :baz]) |
| 17:39 | clojurebot | :foo :bar (:bat :baz) [:foo :bar :bat :baz] |
| 17:40 | alexyk | somnium: ping |
| 17:40 | djork | michaeljaaka: the rules for let and fn bindings are the same |
| 17:40 | alexyk | I get integers back from json as 2.3275269E7, how can I convert them back to ints? |
| 17:41 | alexyk | do we have longs, too? |
| 17:41 | michaeljaaka | yes, I have noticed now |
| 17:41 | michaeljaaka | that I was missing double [] |
| 17:41 | michaeljaaka | [[ all goes here ]] |
| 17:42 | somnium | alexyk: hi |
| 17:43 | alexyk | somnium: so I'm wondering about getting back ints and longs from json ^^ |
| 17:43 | alexyk | from mongo |
| 17:43 | alexyk | although it looks like mongo returns floats |
| 17:44 | alexyk | how in clojure do you check the type of x? |
| 17:44 | devlinsf | (class x) |
| 17:44 | alexyk | yep |
| 17:44 | devlinsf | ,(class {}) |
| 17:44 | clojurebot | clojure.lang.PersistentArrayMap |
| 17:44 | devlinsf | Ooops |
| 17:45 | alexyk | so if I do (def x <very long int>) will it make it long? |
| 17:46 | alexyk | I see if I do (def x (long <very long int>)) then it does |
| 17:46 | the-kenny | ,(class (bigdec 1e100)) |
| 17:46 | clojurebot | java.math.BigDecimal |
| 17:46 | hiredman | (class 1e100M) |
| 17:46 | hiredman | ,(class 1e100M) |
| 17:46 | clojurebot | java.math.BigDecimal |
| 17:47 | alexyk | I just care for long and int for now :) |
| 17:47 | alexyk | (long 2.173617511E9) |
| 17:47 | alexyk | ,(long 2.173617511E9) |
| 17:47 | clojurebot | 2173617511 |
| 17:47 | alexyk | ,(int 2.173617511E9) |
| 17:47 | clojurebot | 2147483647 |
| 17:48 | alexyk | see wha'am sayin'? |
| 17:48 | alexyk | I get back floats from JSON and need to make them either int or long again |
| 17:48 | alexyk | and I don't want to waste bits |
| 17:48 | alexyk | I guess I'll just use longs for the long ones :) |
| 17:49 | somnium | alexyk: I'm not sure, I just tried a test and it came back as expected |
| 17:49 | alexyk | somnium: do you see integrals? I have floats for twit ids and user ids |
| 17:49 | alexyk | :id 2.173617511E9, ... |
| 17:50 | somnium | -> (insert :nums {:x (int 1)}) |
| 17:50 | alexyk | ah, right, you do insert via clojure. I've used mongoimport. |
| 17:50 | alexyk | And it made all numbers floating-point. |
| 17:50 | somnium | ok, so not my fault I hope :) |
| 17:50 | alexyk | somnium: you're fine :) |
| 17:51 | alexyk | I just wonder if you tried mongoimport-ed json |
| 17:51 | hiredman | :| |
| 17:51 | hiredman | best not to be doing float -> int/long conversions |
| 17:52 | alexyk | hiredman: well, it's a cheap way to dodge the question for mongo, I guess. All the digits are there, at least. |
| 17:52 | hiredman | :( |
| 17:52 | somnium | hmm, java.lang.BigDecimals do get converted to doubles though |
| 17:53 | somnium | makes me want to rewrite the encoders in clojure even more |
| 17:53 | alexyk | somnium: what do defprotocol and deftype do which would speed it up? |
| 17:53 | somnium | I've actually taken to using strings and then (read-string) in clojure for sensitive numbers |
| 17:53 | ordnungswidrig | Is there a function to flatten nested lists? Or sth to convert sth to a one-element-list unless it's a list? |
| 17:54 | somnium | alexyk: check assembla and lots of discussion in the logs here and the mailing list |
| 17:54 | alexyk | somnium: ok :) |
| 17:56 | michaeljaaka | ,(defn me[ { :keys [ one two ] } m] (println (:one m)))(me :one 2 :two 3 ) |
| 17:56 | clojurebot | DENIED |
| 17:56 | michaeljaaka | ,(defn me[ { :keys [ one two ] } m] (println (:one m))) |
| 17:56 | clojurebot | DENIED |
| 17:57 | ordnungswidrig | michaeljaaka: you must not use defn |
| 17:57 | michaeljaaka | ok :) I noticed :) |
| 17:57 | michaeljaaka | ,(fn[ { :keys [ one two ] } m] (println (:one m)))(me :one 2 :two 3 ) |
| 17:57 | clojurebot | #<sandbox$eval__6052$fn__6055 sandbox$eval__6052$fn__6055@1655d7e> |
| 17:58 | michaeljaaka | ,((fn[ { :keys [ one two ] } m] (println (:one m)))(me :one 2 :two 3 )) |
| 17:58 | clojurebot | java.lang.Exception: Unable to resolve symbol: me in this context |
| 17:58 | michaeljaaka | ,((fn[ { :keys [ one two ] } m] (println (:one m)))( :one 2 :two 3 )) |
| 17:58 | clojurebot | java.lang.IllegalArgumentException: Wrong number of args passed to keyword: :one |
| 18:00 | michaeljaaka | why this is wrong? |
| 18:01 | hiredman | (:one 2 :two 3) |
| 18:01 | ordnungswidrig | michaeljaaka: the form ( :one 2 :two 3) |
| 18:01 | michaeljaaka | how I should def fun so I have use (myfun :one 2 :two 3) |
| 18:01 | michaeljaaka | I don't want to play with clojurebot (ieave him alone) |
| 18:02 | michaeljaaka | I want just to write one stupid function :( I almost done writing cool program and ended with many args |
| 18:02 | michaeljaaka | and wanted to pass them with symbols |
| 18:02 | michaeljaaka | to make it more readable |
| 18:04 | somnium | ,(-> {:one 1} ((fn [{:keys [one]}] (println "one is" one)))) |
| 18:04 | clojurebot | one is 1 |
| 18:05 | spuz | Hello, all, I've written an article about how I went about optimising my Clojure fractal renderer: http://developmentjungle.wordpress.com/2009/11/24/optimising-mandelbrot/ |
| 18:05 | michaeljaaka | somnium: it is cool |
| 18:06 | spuz | It's most likely that I'm still doing newbie things so any and all feedback is very welcome! |
| 18:06 | michaeljaaka | but how to call it in terms of usage (myfun :one 1 :two 2) |
| 18:06 | michaeljaaka | etc. |
| 18:07 | somnium | michaeljaaka: easiest would be to use defnk in clojure.contrib.def |
| 18:07 | michaeljaaka | somnium: anyways thanks, you explained how to use symboled binding |
| 18:07 | michaeljaaka | oh, so destructuring doesn't help here |
| 18:07 | michaeljaaka | just I wanted to know that |
| 18:07 | somnium | it does, defnk is a macro that destructures for you |
| 18:08 | hiredman | I wish people would just use map destructuring |
| 18:08 | somnium | you have to do [arg1 ... argn & kwargs] |
| 18:08 | hiredman | intead of whatever macros, or apply hash-map |
| 18:08 | hiredman | instead |
| 18:09 | michaeljaaka | ohh, so by default hash-map is a pure solution |
| 18:09 | michaeljaaka | just wanted to know that |
| 18:09 | michaeljaaka | apply on hash-map |
| 18:09 | somnium | hiredman: people like sugar? |
| 18:09 | hiredman | michaeljaaka: no! |
| 18:09 | hiredman | apply hash-map is horrible |
| 18:10 | hiredman | ,((fn [{:keys one}] one) {:one 1}) |
| 18:10 | clojurebot | java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol |
| 18:10 | hiredman | ,((fn [{:keys [one]}] one) {:one 1}) |
| 18:10 | clojurebot | 1 |
| 18:10 | hiredman | :P |
| 18:10 | somnium | hiredman: the nicest thing about defnk is the dryness, default args and automatic symbols in ~@ |
| 18:10 | michaeljaaka | but is used in core.clj |
| 18:10 | michaeljaaka | i like to learn by example |
| 18:11 | hiredman | :| |
| 18:11 | hiredman | spuz: looks nice |
| 18:11 | michaeljaaka | ,( (fn[ { :keys [ one two ] } m] (println one)) [ :one 2 :two 3] ) |
| 18:11 | clojurebot | java.lang.IllegalArgumentException: Wrong number of args passed to: sandbox$eval--6103$fn |
| 18:11 | michaeljaaka | doesn't work |
| 18:12 | hiredman | for many many reasons |
| 18:12 | hiredman | michaeljaaka: I think you should become more familar with more basic things before you start with destructuring |
| 18:13 | michaeljaaka | well for example? |
| 18:13 | hiredman | for example, [:one 2 :two 3] is a vector |
| 18:14 | ordnungswidrig | spuz: nice post. |
| 18:14 | hiredman | the fn you created there takes two args, but you only passing it a single vector |
| 18:14 | hiredman | even if the fn took one arg, you trying to do map destructuring on a vector |
| 18:15 | spuz | hiredman: thanks, I think the main interesting part is digging into Clojure's internals with VisualVM. Of course I'm not an expert but I thought it would be useful to show my findings |
| 18:16 | hiredman | spuz: yeah, exploring clojure's call tree++ |
| 18:17 | michaeljaaka | ok |
| 18:19 | michaeljaaka | I will just use |
| 18:19 | michaeljaaka | ,((fn[ & a ] (let [ b (apply (hash-map) a) ] :one b )) :one 2) |
| 18:19 | clojurebot | 2 |
| 18:19 | ordnungswidrig | good night everyone |
| 18:19 | michaeljaaka | bye! |
| 18:19 | hiredman | michaeljaaka: :| |
| 18:19 | kzar | <h1>I wonder what happens to the logs</h1></body></html> |
| 18:19 | hiredman | (hash-map) is a bug there |
| 18:20 | michaeljaaka | so it is in core.clj :) |
| 18:20 | hiredman | no |
| 18:20 | hiredman | the idiom is (apply hash-map … |
| 18:20 | hiredman | not (apply (hash-map) … |
| 18:20 | hiredman | seriously |
| 18:21 | michaeljaaka | ah |
| 18:21 | michaeljaaka | ok |
| 18:21 | hiredman | you need more practice just reading and understanding clojure code |
| 18:21 | michaeljaaka | in core.clj is hash-map not (hash-map) |
| 18:21 | hiredman | I would suggest sitting down with project euler or similar |
| 18:21 | michaeljaaka | yeah, practicing :) just writing google map reduce in clojure |
| 18:21 | michaeljaaka | almost done ;) |
| 18:22 | hiredman | don't worry about destructuring or keyword args till you can read and write code |
| 18:22 | hiredman | michaeljaaka: I can almost guarantee it will be full of bugs if your interactions with clojurebot are a representative sample |
| 18:22 | michaeljaaka | with true distribution between machines |
| 18:23 | michaeljaaka | no problem ;) I'm just learning language, often just asking and making stupid questions |
| 18:23 | michaeljaaka | but finally gots alwasy this "oh this is it" |
| 18:24 | hiredman | java.lang.IllegalStateException: case already refers to: #'clojure.core/case in namespace: ring.jetty (jetty.clj:1) |
| 18:24 | hiredman | grrrr |
| 18:26 | _ato | michaeljaaka: btw, something I've noticed with your code is the spacing. Normal Clojure style is to do: (defn [arg1 arg2] ...) rather than (defn[ arg1 arg2 ] ...) which you seem to be doing. Not a huge deal but if you get used to the same style everyone else uses than it will be easier for you to read their code and for them to read your code. :-) |
| 18:27 | michaeljaaka | yeah, I must change it, the same is with writing doc for function, I need to learn writing doc before fn binding |
| 18:27 | michaeljaaka | fn params |
| 18:27 | the-kenny | Are there some "coding conventions" for clojure like for Common Lisp? |
| 18:31 | KirinDave1 | How does one go about converting a set to a list? |
| 18:31 | _ato | the-kenny: not specific clojure ones AFAIK. The conventional style is basically the same as Lisp/Scheme style though: http://mumble.net/~campbell/scheme/style.txt |
| 18:31 | _ato | ,(seq #{1 2 3}) |
| 18:31 | clojurebot | (1 2 3) |
| 18:32 | KirinDave1 | Ah, I see. |
| 18:32 | the-kenny | _ato: Yeah, I know the conventions for Lisp, but I think Clojure needs some improvements (hashmaps, for example) |
| 18:32 | _ato | KirinDave1: ^ |
| 18:32 | the-kenny | Maybe I'll start a page in the Wiki |
| 18:32 | the-kenny | :) |
| 18:33 | _ato | the-kenny: good idea. :-) Do you mean either breaking the line or using commas with hashmaps: {:k1 :v1, :k2 :v2} to pair keys and values? |
| 18:35 | the-kenny | _ato: Yeah, and also how to write and indent hashmaps with one element per line.. clojure-mode seems to have problems with "{\n:foo 42\n}" so I'm using "{:foo 42\n:bar 23} currently. |
| 18:35 | the-kenny | I'm interested in what other people think and use |
| 18:36 | Chousuke | I think {:foo 'bar\n :zonk ...} is the most common |
| 18:36 | Chousuke | generally, you don't separate the opening bracket from the first item |
| 18:37 | _ato | yeah, I tend to treat () [] {} #{} etc all the same way. no whitespace or newlines at the start or end |
| 18:37 | Chousuke | some people seem to like writing function definitions like (defn foo[params] ...) but I think that's just misleading :) |
| 18:37 | Chousuke | it makes foo[bar] look like some kind of special syntax |
| 18:38 | the-kenny | Yes, it reminds me of C++ or Java. |
| 18:40 | KirinDave1 | ,(isa? #"" java.util.regex.Pattern) |
| 18:40 | clojurebot | false |
| 18:41 | KirinDave1 | (class #"") |
| 18:41 | KirinDave1 | ,(class #"") |
| 18:41 | clojurebot | java.util.regex.Pattern |
| 18:41 | KirinDave1 | So uh, how do I know if I have a regex? |
| 18:41 | Chousuke | heh, that lisp style guide says to avoid point-free style :P |
| 18:41 | _ato | ,(instance? #"" java.util.regex.Pattern) |
| 18:41 | clojurebot | java.lang.ClassCastException: java.util.regex.Pattern cannot be cast to java.lang.Class |
| 18:42 | _ato | did I get backwards |
| 18:42 | _ato | ,(instance? java.util.regex.Pattern #"") |
| 18:42 | clojurebot | true |
| 18:42 | KirinDave1 | Ahh |
| 18:42 | KirinDave1 | Yeah I guess that's it then. |
| 18:42 | KirinDave1 | Weird, I thought that isa? did that too. |
| 18:42 | _ato | ,(isa? java.util.regex.Pattern #"") |
| 18:42 | clojurebot | false |
| 18:44 | _ato | I agree with generally avoiding point free style. I don't mind the occasionally partial, or comp with just two functions in it, but if you chain together a whole line of comps and partials it's really hard to understand what's going on |
| 18:45 | Chousuke | the problem is made worse by the fact that point-free style in clojure is just verbose :P |
| 18:51 | KirinDave1 | :\ |
| 18:51 | KirinDave1 | The most awkward part of learning a new language is in those first concrete modules you write and you go ":\ Man I wrote this the wrong way." |
| 18:52 | tomoj | is it evil to rely on hashCode for vectors being consistent across JVM executions? |
| 18:53 | Chousuke | yes? |
| 18:54 | Chousuke | IIRC the contract for hashCode specifically states that, but I'm not sure. |
| 18:54 | tomoj | yeah the contract specifically states that it doesn't need to be consistent, but it seems that it is for vectors |
| 18:55 | Chousuke | That seems very likely to break. |
| 18:56 | tomoj | guess i can prn and hash that string.. hmm |
| 18:58 | hiredman | hmmm |
| 18:58 | hiredman | actually |
| 18:59 | technomancy | clojurebot: style is http://mumble.net/~campbell/scheme/style.txt |
| 18:59 | clojurebot | Ack. Ack. |
| 19:00 | technomancy | hiredman: we're coming up on clojurebot's first birthday soon, aren't we? |
| 19:02 | hiredman | clojurebot: if you where a super hero what would your origin story be? |
| 19:03 | hiredman | long sentences like that peg the fuzzer hard |
| 19:03 | technomancy | is it still thinking? |
| 19:03 | hiredman | yep |
| 19:04 | somnium | is he smart enough for s/where/were? |
| 19:04 | hiredman | java's cpu time is falling |
| 19:04 | hiredman | huh |
| 19:04 | hiredman | out of heap space |
| 19:04 | hiredman | :( |
| 19:05 | the-kenny | :( |
| 19:05 | hiredman | clojurebot: your origin story? |
| 19:05 | clojurebot | http://clojure-log.n01se.net/date/2008-11-21.html#13:04 |
| 19:05 | hiredman | huh |
| 19:05 | technomancy | oh, my clojure birthday was last week! |
| 19:06 | technomancy | I thought it was this week. time to cancel the party. =( |
| 19:06 | the-kenny | If clojurebot gains the ability to modify his own source code, he will surely become skynet |
| 19:06 | hiredman | clojurebot: clojurebot |has| a lot of features |
| 19:06 | clojurebot | In Ordnung |
| 19:07 | somnium | ~terminator |
| 19:07 | clojurebot | excusez-moi |
| 19:08 | the-kenny | clojurebot: You |will not| become skynet |
| 19:08 | clojurebot | In Ordnung |
| 19:08 | technomancy | "so far it's hard to keep a bug alive long enough for a tracker to be useful. They tend to be fixed within a day or two, if not hours or minutes." <= from a year ago. =( |
| 19:09 | _ato | :( |
| 19:10 | hiredman | clojurebot: you? |
| 19:10 | clojurebot | You will not become skynet |
| 19:10 | the-kenny | clojurebot: Do you plan to evolve to skynet? |
| 19:10 | clojurebot | You will not become skynet |
| 19:11 | danlarkin | technomancy: ha!! |
| 19:15 | somnium | clojurebot: clojurebot |will| become skynet |
| 19:15 | clojurebot | Alles klar |
| 19:17 | the-kenny | Oh no :( |
| 19:17 | somnium | its kind of scary he responded with Alles klar |
| 19:20 | the-kenny | Ja, das stimmt. |
| 19:20 | the-kenny | ;) |
| 20:02 | cark | hiredman: what are the pipes for when talking to clojurebot ? |
| 20:02 | krumholt__ | ,(((fn [r] ((fn [f] (f f)) (fn [f] (r (fn [x] ((f f) x)))))) (fn [f] (fn [n] (if (= n 0) 1 (* n (f (- n 1))))))) 5) |
| 20:02 | clojurebot | 120 |
| 20:18 | hiredman | cark: arbitrary predicates |
| 20:18 | hiredman | clojurebot defaults to X is Y |
| 20:18 | hiredman | but with the pipes you can say X | Z | Y |
| 20:18 | cark | oh i see |
| 20:19 | cark | clojurebot: clojurebot? |
| 20:19 | clojurebot | clojurebot has a lot of features |
| 20:19 | cark | allright thanks =) |
| 20:19 | cark | does it do the "also" part automatically now ? |
| 20:20 | cark | i mean, no overwriting existing definitions ? |
| 20:22 | chouser | rhickey: if we give up on handlers fixing state, whether queue or synchronous model, most of the complexity goes away. error actions always "never happened", no watchers, no sends |
| 20:22 | hiredman | cark: yes |
| 20:23 | hiredman | you can remove a definition if you know the exact tripple |
| 20:23 | hiredman | triple |
| 20:23 | cark | ah so i'll need to be sneaky when adding definitions aboutu you ! |
| 20:23 | cark | thanks anyways =) |
| 20:29 | Anniepoo | ,(set! *ns* "tacos for lunch") |
| 20:29 | clojurebot | "tacos for lunch" |
| 20:30 | Anniepoo | ,(+ 1 2) |
| 20:30 | clojurebot | 3 |
| 20:30 | Anniepoo | 8c) |
| 20:32 | tomoj | mm tacos |
| 20:32 | chouser | what have you done!? |
| 20:32 | chouser | ,`foo |
| 20:32 | clojurebot | sandbox/foo |
| 20:32 | chouser | hm |
| 20:33 | Anniepoo | just wondered if that crashed clojurebot |
| 20:33 | Anniepoo | I'm using hiredman's sandbox for a thing I'm building |
| 20:33 | tomoj | (set! *ns* "foo") blows up for me |
| 20:34 | tomoj | and *ns* is left unchanged |
| 20:34 | Anniepoo | throws a java exception, yet |
| 20:34 | tomoj | ,*ns* |
| 20:34 | clojurebot | #<Namespace sandbox> |
| 20:35 | tomoj | weird that you still get a return value |
| 20:36 | Anniepoo | I'm still trying to find a better way to prevent an evaluation from making global changes than clojurebot uses |
| 20:36 | Anniepoo | clojurebot does a macroexpand, then looks for 'bad forms' |
| 20:36 | Anniepoo | this seems iffy to me |
| 20:36 | hiredman | it is |
| 20:36 | cark | what's your use case for sandboxing ? |
| 20:37 | Anniepoo | I'm trying to make an 'injectable code' server |
| 20:37 | Anniepoo | you send me a form, I evaluate it and send you the result |
| 20:37 | cark | does the injected code need to be fast ? |
| 20:38 | Anniepoo | hmmm.... why, you know a slow way? |
| 20:38 | cark | yes =) |
| 20:38 | Anniepoo | what's the slow way? |
| 20:38 | cark | do your own lisp interpreter, only reuse the clojure reader |
| 20:39 | cark | sounds like a lot of work, but it really isn't |
| 20:39 | Anniepoo | that might actually work |
| 20:39 | Anniepoo | it's not as elegant as allowing arbitrary clojure |
| 20:39 | Anniepoo | I could reverse hiredman's scheme, make a list of everything that's OK |
| 20:40 | cark | but you have perfect control |
| 20:40 | hiredman | you could send the code to appengine to run :P |
| 20:40 | hiredman | let google worry about the sandboxing |
| 20:40 | Anniepoo | what's appengine? |
| 20:40 | hiredman | ~google appengine |
| 20:40 | clojurebot | First, out of 327000 results is: |
| 20:40 | clojurebot | Google App Engine - Google Code |
| 20:40 | clojurebot | http://code.google.com/appengine/ |
| 20:40 | hiredman | googles hosting thing |
| 20:41 | Anniepoo | ah, ok, sorry, didn't get it, yes yes |
| 20:41 | hiredman | it's free up to a certain point |
| 20:41 | hiredman | which is pretty cool |
| 20:41 | Anniepoo | well, I'm acutally not concerned about the java sandboxing, which, as you know, is pretty trivial |
| 20:41 | Anniepoo | it's actually a bigger problem to sandbox the clojure |
| 20:42 | Anniepoo | in an ideal world I'd make a new JVM environment for each session |
| 20:42 | hiredman | yeah, but you can just ship the clojure code to google, and it's their problem |
| 20:42 | Anniepoo | so if you ruin your environment it's your problem |
| 20:42 | Anniepoo | no, I'm not worried about violating the java sandbox |
| 20:43 | Anniepoo | I'm worried about somebody clobbering my clojure server |
| 20:43 | hiredman | I know, but the clojure code can do whatever it wants on google's jvm in the sky |
| 20:43 | hiredman | google limits execution time to something like 30 seconds |
| 20:43 | hiredman | and has other limitations as well |
| 20:43 | Anniepoo | ok, I could do the same thing locally, spawn a jvm |
| 20:43 | Anniepoo | and install a security manager, then eval the code |
| 20:43 | cark | mhh you can instanciate a clojure environment from java, so i guess you could do it from clojure as well, so i guess you'd get a new instance of the whole thing ? |
| 20:44 | Anniepoo | that works, but is massively inefficient |
| 20:44 | hiredman | I bet shipping the code to google would actually be faster than ramping up a new jvm |
| 20:44 | Anniepoo | good point, cark |
| 20:44 | Anniepoo | if you can do that |
| 20:44 | Anniepoo | but I haven't figured out how to |
| 20:45 | Anniepoo | how would I make a new environment? That's what I really want |
| 20:45 | hiredman | make a new classloader and load clojure.lang.RT |
| 20:45 | Anniepoo | really? |
| 20:45 | Anniepoo | Hmm.... |
| 20:45 | Anniepoo | OK |
| 20:45 | Anniepoo | sounds like deep doings, but I'm up for it |
| 20:47 | cark | mhh nope =( |
| 20:47 | cark | http://markmail.org/message/madkidutwpp2yd44?q=thread:tx23zaxf77b6widh |
| 20:49 | hiredman | I dunno about that, but clojure runtime is initilized via a static init block in RT |
| 20:49 | Anniepoo | ok, now gotta find some sorta docs on clojure.lang.RT |
| 20:49 | hiredman | pffft |
| 20:49 | hiredman | docs |
| 20:52 | Anniepoo | 8cP Somehow reading the source code to RT strikes me as likely to induce paranoid schizophrenia or warts or soemthing |
| 20:52 | hiredman | *shrug* |
| 20:55 | hiredman | (== clojure.lang.RT (-> (ClassLoader/getSystemClassLoader) (.loadClass "clojure.lang.RT"))) |
| 20:55 | hiredman | er |
| 20:55 | hiredman | user=> (== clojure.lang.RT (-> (ClassLoader/getSystemClassLoader) (.loadClass "clojure.lang.RT"))) |
| 20:55 | hiredman | false |
| 20:55 | hiredman | user=> |
| 20:58 | Anniepoo | ooh, are you saying that if I call RT:load that's all I gotta do here? |
| 20:59 | hiredman | possibly |
| 21:01 | Anniepoo | hmm... Ah, you're saying make a new classloader and then use it to load RT, which will make a 'new' RT class? |
| 21:01 | Anniepoo | I wonder if that makes a memory leak |
| 21:02 | Anniepoo | after I've processed a few thousand of these I've got my memory full of class definitions of RT |
| 21:03 | hiredman | user=> (-> (ClassLoader/getSystemClassLoader) (.loadClass "clojure.lang.RT") (wall-hack-method :var [String String] nil "clojure.core" "+") (apply '(1 2 3 4))) |
| 21:03 | hiredman | 10 |
| 21:03 | hiredman | user=> |
| 21:04 | hiredman | actually |
| 21:06 | hiredman | you'll want (proxy [ClassLoader] [(ClassLoader/getSystemClassLoader)]) |
| 21:06 | Anniepoo | ok, I'm getting 10% of this, but will go do my homework. Keep talkin! |
| 21:06 | hiredman | Classes can be GC'ed, but I forget the provisos |
| 21:07 | Anniepoo | I'll find out how |
| 21:07 | chouser | classes get GCed when their classloader gets GCed |
| 21:07 | chouser | I think |
| 21:08 | hiredman | ok, yeah, that is why you need the proxy |
| 21:08 | hiredman | so you have an instance of the classloader you can let go of |
| 21:08 | Anniepoo | ah |
| 21:08 | hiredman | instead of the bare system classloader |
| 21:09 | Anniepoo | nifty nifty!!! |
| 21:09 | Anniepoo | that's what I've been looking for |
| 21:10 | hiredman | maybe not |
| 21:10 | Anniepoo | hmm, why not? |
| 21:11 | hiredman | it looks like altering the metadata on the var named by clojure.core/+ from the new RT alters the meta data on the old one |
| 21:11 | hiredman | (implying they are the same) |
| 21:11 | hiredman | :| |
| 21:12 | Anniepoo | 8c( not good |
| 21:12 | hiredman | oh |
| 21:12 | hiredman | I wonder if its a result of var interning from compile to runtime |
| 21:12 | hiredman | anyway, *shrug* |
| 21:13 | hiredman | ah! |
| 21:13 | hiredman | yeah, it must be |
| 21:13 | _ato | are you trying to run two seperate clojure instances in the one JVM? |
| 21:13 | _ato | http://gist.github.com/240818 |
| 21:13 | _ato | ^ that's what I was playing with the other day |
| 21:14 | Anniepoo | wow, sweet, ato! |
| 21:16 | Anniepoo | ok, this looks promising. |
| 21:17 | Anniepoo | So, I wonder what the memory overhead will be for each of these instances I have laying around |
| 21:18 | _ato | note that you have to use java interop stuff to "talk" to the "inner" Clojure as they're completely segregated, the data structures in the outer clojure can't be passed directly to the inner one AFAIK. But you could of course write a function that prn's some code to a string then does a read-string and eval on it in the inner Clojure. |
| 21:19 | Anniepoo | yes, |
| 21:19 | Anniepoo | I'm going to be evaling a string anyway |
| 21:19 | Anniepoo | I want to make a sort of 'rmi' for clojure |
| 21:20 | Anniepoo | you send me a string, I eval it (suitably sandboxed) and return the value to you |
| 21:20 | Anniepoo | the hard part is the 'suitably sandboxed' |
| 21:22 | _ato | ah yeah, you'd probably to proxy URLClassLoader to setup it's permissions to block access to files and sockets and such |
| 21:22 | _ato | also note that creating a fresh classloader and loading a fresh copy of clojure in it can take a while, it's about 600ms on my PC |
| 21:22 | Anniepoo | oochie. 8cP afraid of that |
| 21:24 | Anniepoo | maybe I can make a custom version of RT |
| 21:26 | Anniepoo | take all the static members and swap them out |
| 21:27 | hiredman | :| |
| 21:27 | hiredman | the time is not in loading RT, it is loading everything else |
| 21:27 | hiredman | when you load RT you are loading all the classes clojure uses |
| 21:28 | Anniepoo | yes, I suppose. And it smells of back to the bad-forms method |
| 21:28 | hiredman | and for interning stuff like Var you need to have them seperate |
| 21:28 | Anniepoo | the interpreter seems to make more and more sense |
| 21:29 | Anniepoo | 8cD What we need is clojure in clojure! |
| 21:29 | hiredman | you could pool RTs |
| 21:29 | Anniepoo | no, because the point is to have a 'fresh' one |
| 21:29 | _ato | you could pre-create a pool of them |
| 21:29 | _ato | use one |
| 21:29 | _ato | and throw it away |
| 21:29 | hiredman | spin up two or three, every time you spin up one |
| 21:29 | _ato | create a new |
| 21:29 | _ato | etc |
| 21:30 | Anniepoo | true, but that limits my sustained rate, and works the server |
| 21:30 | Anniepoo | I'm beginning to think the interpreter way is the right way |
| 21:30 | _ato | there might be a way to put most of the classes in a parent classloader and just the stuff that changes like RT itself in multiple child classloaders |
| 21:30 | Anniepoo | make a toy lisp interpreter in Clojure. |
| 21:31 | _ato | so they share most classes |
| 21:32 | _ato | actually that probably wouldn't work as RT and the collections are pretty tightly coupled, the collections call into RT |
| 21:32 | kzar | Kind of a dumb question but I'm writing a simple recursive function and I'm trying to create a lazy sequence of numbers. I tried doing something like (lazy-seq x (recur (+ x 1))) but it doesn't work because x is an integer. What's the right way around that? |
| 21:33 | _ato | use the function name instead of recur |
| 21:33 | hiredman | kzar: it doesn't work because you can't call recur within lazy-seq |
| 21:33 | _ato | recur does tail call optimisation, but a lazy-seq exits the function so it doesn't make sense |
| 21:34 | Anniepoo | well, thanks all, this has been helpful. I'll explore the options |
| 21:34 | _ato | oh |
| 21:34 | _ato | and you need: (lazy-seq (cons x (recur (+ x 1))))) |
| 21:34 | _ato | kzar: lazy-seq doesn't cons for you |
| 21:35 | _ato | err, I of course mean: (lazy-seq (cons x (my-fn (+ x 1))))) |
| 21:35 | hiredman | "Elapsed time: 1.846638 msecs" |
| 21:35 | kzar | Sweet gotya, thanks |
| 21:36 | hiredman | RT loads pretty fast here |
| 21:36 | _ato | hiredman: ah awesome |
| 21:36 | _ato | maybe it's fast if you use the same version |
| 21:36 | _ato | it can probably used the already loaded classes |
| 21:37 | _ato | I was loading 1.0 inside 1.1 |
| 21:38 | zaphar_ps | is the clojure documentation available as a downlaod anywhere? |
| 21:38 | zaphar_ps | that would be really useful |
| 21:39 | Anniepoo | hiredman, you're probably only having to reload the one class |
| 21:39 | Anniepoo | but since the versions are diff ato's reloading the world? |
| 21:40 | _ato | zaphar_ps: try this: http://github.com/ksuzuki/Save-cljsites |
| 21:41 | _ato | zaphar_ps: there's also various other suggestions on the google group: http://groups.google.com/group/clojure/search?group=clojure&q=offline+documentation |
| 21:42 | _ato | zaphar_ps: if you're using emacs + slime move the cursor over the name of a function and press: C-c C-d C-d (that obviously doesn't let you search though) |
| 21:42 | zaphar_ps | ahh nifty that's like the wget option I was considering |
| 21:43 | zaphar_ps | _ato: yeah I use vimclojure which has similar |
| 21:43 | zaphar_ps | but like you say it doesn't allow searching or browsing |
| 21:43 | kzar | _ato: That worked but when I took too many from the lazy sequence I got a stack overflow. Your right that recur wouldn't work because it gives me an error so is there an alternative? |
| 21:43 | _ato | kzar: strange... you shouldn't get a stackoverflow, can you pastebin your whole function |
| 21:43 | _ato | ? |
| 21:45 | Anniepoo | anybody know of a lisp interpreter in clojure? I'm beginning to like that tack a lot |
| 21:47 | lisppaste8 | kzar pasted "fib" at http://paste.lisp.org/display/91070 |
| 21:48 | _ato | ah, I get a heap overflow not a stack overflow |
| 21:49 | kzar | _ato: whoops sorry me too |
| 21:50 | _ato | try reduce instead of apply |
| 21:50 | _ato | I suspect apply is holding onto the head of the sequence |
| 21:52 | kzar | _ato: Hmm that's taking ages to run |
| 21:53 | kzar | _ato: hope my macbook doesn't blow a hole in my crappy desk, it's whiring up ominously |
| 21:54 | _ato | well you're asking it to sum 4 million fib numbers |
| 21:54 | _mst | kzar: I don't think you need to sum the first 4,000,000 numbers to solve that problem ;) |
| 21:54 | _ato | the final answer is going to be enormous |
| 21:55 | kzar | I guess so but here's the question: "Find the sum of all the even-valued terms in the sequence which do not exceed four million." |
| 21:55 | _mst | yep, but even fib(100) exceeds four million by loads |
| 21:56 | kzar | oh I read it while the number in the sequence is less than four million but it meant while the sum was less than four million |
| 21:57 | _ato | it does mean the numbers in the sequence are less than four million |
| 21:57 | _ato | it doesn't mean while the *length* of the sequence is less than four million |
| 21:57 | kzar | yea gotya :/ I'm glad this is logged for everyone to see |
| 21:57 | _ato | you probably want (take-while #(< % 4000000) ...) instead of (take 4000000 ...) |
| 21:58 | _mst | less ambiguously: (reduce + (take-while #(< % 4000000) (filter even? (fib)))) ;) |
| 22:00 | kzar | oh cool, that's pretty powerful |
| 22:00 | lisppaste8 | kzar annotated #91070 "better" at http://paste.lisp.org/display/91070#1 |
| 22:21 | alexyk | how do you print to stderr? |
| 22:30 | zaphar_ps | alexyk: (.println (System/err) "foo") |
| 22:30 | zaphar_ps | off the top of my head that should work |
| 22:30 | zaphar_ps | uses javas stderr print stream |
| 22:31 | alexyk | thx! |
| 22:32 | zaphar_ps | http://clojure.org/java_interop |
| 22:32 | zaphar_ps | that would probably be useful |
| 22:32 | alexyk | so here .println is called on System/err? is that the syntax? |
| 22:32 | zaphar_ps | alexyk: yeah |
| 22:40 | zaphar_ps | alexyk: after further reading *err* represents stderr in clojure as well |
| 22:41 | alexyk | zaphar_ps: can we use (print ...) with it somehow? |
| 22:41 | alexyk | weird: (print *err* "au") gets me a: #<PrintWriter java.io.PrintWriter@2db7ae22> aunil |
| 22:42 | zaphar_ps | you can .println with it |
| 22:42 | zaphar_ps | but print doesn't take a stream it assumes *out* |
| 22:43 | somnium | you can also do (binding [*out* *err*] ...) |
| 22:43 | zaphar_ps | somnium: yeah |
| 22:45 | alexyk | ah ok it just printed *err* |
| 22:47 | zaphar_ps | code? |
| 22:50 | alexyk | I mean representation of *err* is #<PrintWriter java.io.PrintWriter@2db7ae22> |
| 22:52 | zaphar_ps | alexyk: right |
| 23:19 | kzar | how could you take the last two items in a sequence? |
| 23:20 | defn | nthrest |
| 23:20 | defn | err not what you were asking i suppose |
| 23:24 | _mst | if you happen to have a vector: (take 2 (rseq [1 2 3 4 5])) |
| 23:25 | defn | (reverse seq), (take 2 seq) |
| 23:25 | defn | oh yeah, rseq |
| 23:25 | defn | you'll probably wanna reverse the final output from _mst's though |
| 23:26 | defn | ,(reverse (take 2 (rseq [1 2 3 4 5 6]))) |
| 23:26 | clojurebot | (5 6) |
| 23:29 | defn | you also could (let [sz (count [1 2 3 4 5 6])] (rest (split-at (- sz 2) [1 2 3 4 5 6]))) |
| 23:29 | defn | ,(let [sz (count [1 2 3 4 5 6])] (rest (split-at (- sz 2) [1 2 3 4 5 6]))) |
| 23:29 | clojurebot | ((5 6)) |
| 23:29 | defn | or something like that |
| 23:32 | JAS415 | you could also do (drop (-(count coll) 2) coll) |
| 23:32 | zaphar_ps | why do read and readline not accept a java.io.FileReader? |
| 23:34 | JAS415 | have you looked at the duck-streams contrib module? |
| 23:34 | defn | ^^ |
| 23:34 | zaphar_ps | JAS415: no I haven't |
| 23:35 | JAS415 | it might be useful to you |
| 23:38 | defn | ,(let [size (count [1 2 3 4 5 6])] (subvec (- size 2) size [1 2 3 4 5 6])) |
| 23:38 | clojurebot | java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IPersistentVector |
| 23:38 | defn | doh |
| 23:39 | JAS415 | other way round |
| 23:47 | eno__ | ,(let [v [1 2 3 4 5 6] size (count v)] (subvec v (- size 2))) |
| 23:47 | clojurebot | [5 6] |