Re: clojure.contrib.sql insert id
On Apr 20, 8:51 pm, Remco van 't Veer wrote: > I am doing the following after an insert for a Derby database: > > (sql/with-query-results res > ["VALUES IDENTITY_VAL_LOCAL()"] > (first (vals (first res > > For MySQL it would be something like: > > (sql/with-query-results res > ["SELECT LAST_INSERT_ID()"] > (first (vals (first res > Thanks Remco. I'm using H2 and its seems possible to do something similar by accessing the INFORMATION_SCHEMA. However, this also feels wrong to me so I'm trying the JDBC route which should be more consistent across databases. My first working attempt is at: http://gist.github.com/373564#file_sql.clj It contains a alternative to insert-records called 'insert-record' which returns a database id and a macro that wraps up multiple inserts in a transaction. The macro doesn't feel very idiomatic so I'd welcome any feedback on how to change it. - extended.sql/insert-record ([table record]) Equivalent of clojure.contrib.sql/insert-records that only inserts a single record but returns the autogenerated id of that record if available. - extended.sql/insert-with-id ([db & table-records]) Macro Insert records within a single transaction into the database described by the given db spec. The record format is :table { record-hash }. The record hashes can optionally access a hashmap 'id' which holds the autogenerated ids of previous inserts keyed by the table name. e.g. (insert-with-id db-spec :department {:name "xfiles" :location "secret"} :employee {:department (id :department) :name "Mr X"}) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: clojure.contrib.sql insert id
Nice! That's a lot better than depending on some quirky sql construct. Thanks, Remco Saul Hazledine writes: > On Apr 20, 8:51 pm, Remco van 't Veer wrote: >> I am doing the following after an insert for a Derby database: >> >> (sql/with-query-results res >> ["VALUES IDENTITY_VAL_LOCAL()"] >> (first (vals (first res >> >> For MySQL it would be something like: >> >> (sql/with-query-results res >> ["SELECT LAST_INSERT_ID()"] >> (first (vals (first res >> > > Thanks Remco. I'm using H2 and its seems possible to do something > similar by accessing the INFORMATION_SCHEMA. However, this also feels > wrong to me so I'm trying the JDBC route which should be more > consistent across databases. My first working attempt is at: > > http://gist.github.com/373564#file_sql.clj > > It contains a alternative to insert-records called 'insert-record' > which returns a database id and a macro that wraps up multiple inserts > in a transaction. The macro doesn't feel very idiomatic so I'd welcome > any feedback on how to change it. > > - > extended.sql/insert-record > ([table record]) > Equivalent of clojure.contrib.sql/insert-records that only inserts a > single >record but returns the autogenerated id of that record if > available. > > - > extended.sql/insert-with-id > ([db & table-records]) > Macro > Insert records within a single transaction into the database > described by >the given db spec. The record format is :table { record-hash }. >The record hashes can optionally access a hashmap 'id' which holds > the >autogenerated ids of previous inserts keyed by the table name. e.g. > > (insert-with-id db-spec > :department {:name "xfiles" >:location "secret"} > :employee {:department (id :department) >:name "Mr X"}) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: clojure.contrib.sql insert id
On Apr 21, 11:48 am, Remco van 't Veer wrote: > Nice! That's a lot better than depending on some quirky sql construct. Agreed. There's just one potential issue (which is the same issue I have with clojure.contrib.sql): it doesn't quote the column or table names, meaning you can't use such nice column keys as :user-id I smashed all of it into my modified version of clojure.contrib.sql: http://gist.github.com/373677 -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Try + finally question
Hi, I'm using an API to connect to a server which does not provide constructors, just static methods to get & close connections. How can I do something like ... (try (let [conn (API/getConnection ..)] ()) (catch ..) (finally (if conn (API/closeConnection conn Problem is that conn is unavailable in the finally context. Is there any easy workaround which doesn't involve defing a global conn. - Thanks -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
duck-streams missing from clojure-contrib.jar file
Hi, I'm new to Clojure. I've been trying to go through the Programming Clojure book and have run into a problem that I hope someone can fix. I'm trying to use duck-streams, but it is missing from the clojure- contrib JAR file (at least in build #81). I have listed the contents of the JAR file and confirmed that it is not in there. All the documentation that I read seems to indicate that duck-streams is not deprecated. Thanks for any help, Neal -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Arguments for < and > et al
I've been writing a program that requires the use of java.util.Calendar and its descendent java.util.GregorianCalendar. One thing I'd hoped to do was compare two Calendar objects with <, but the compiler complained that the arguments to < didn't inherit from Number which was a surprise to me because Calendar does inherit from java.lang.Comparable which in java land would be sufficient to enable it to be compared with other members of its class using the built in java comparison operators. Since I know that clojure has other operations that deal with comparable, I assume this is a conscious decision, but I question why it should be so. Regards, Bill -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Interesting Facebook blog post on Concurrency (mentions Clojure)
H! :D -- Clojure uses MVCC, which may help with this. http://en.wikipedia.org/wiki/Multiversion_concurrency_control But as Hickey points out, no one really knows yet because there aren't enough high-core machines doing real work in the field. http://groups.google.com/group/clojure/msg/cd3e77afb75441d8 I put that second sentence in more as a joke than a Deep Insight; it's a reference to a silly song I like called "The Sweater Song": "If you want to destroy my sweater / Hold this thread as I walk away." Cheers, Carlos On Apr 13, 12:02 am, Baishampayan Ghose wrote: > Hi, > > This is an interesting article on the problems associated with > concurrency and some of the current solutions. > > http://www.facebook.com/notes/facebook-engineering/a-dismal-guide-to-... > > It mentions Clojure for a bit and says this about the general idea > behind STMs - > > "... STM has its own special problems, like how to perform those > commit/abort/retry cycles efficiently on thousands of threads. It's fun > to imagine pathological conflict scenarios in which long chains of > transactions unravel like a cheap sweater." > > Would anyone like to comment on how that affects the Clojure STM (if at > all)? > > Regards, > BG > > -- > Baishampayan Ghose -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
ka writes: > How can I do something like ... > > (try > (let [conn (API/getConnection ..)] > ()) > (catch ..) > (finally (if conn (API/closeConnection conn > > Problem is that conn is unavailable in the finally context. Why not just have two try blocks? (try (let [conn (API/getConnection ..)] (try () (finally (API/closeConnection conn (catch ...)) For these sorts of things I usually try to use with-open, or if with-open is not applicable do my own similar macro: (defmacro with-api-connection [conn-sym arg1 arg2 & body] `(let [~conn-sym (API/getConnection ~arg1 ~arg2)] (try ~...@body (finally (API/closeConnection ~conn-sym) So then you never forget to close the connection: (try (with-api-connection conn ... (... do something with conn ...)) (catch ...)) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: duck-streams missing from clojure-contrib.jar file
Hi, On 21 Apr., 01:37, Neal wrote: > All the documentation that I read seems to indicate that duck-streams > is not deprecated. c.c.ducks-streams is now named c.c.io. Sincerely Meikel -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: duck-streams missing from clojure-contrib.jar file
Hi Neal, Neal writes: > I'm trying to use duck-streams, but it is missing from the clojure- > contrib JAR file (at least in build #81). I have listed the contents > of the JAR file and confirmed that it is not in there. It sounds like you're using a 1.2 pre-release snapshot build of clojure-contrib. There's currently some refactoring going on to better organize contrib, now that it's a little more mature. Most of clojure.contrib.duck-streams has now become clojure.contrib.io. I suggest you use the stable 1.1 releases of both Clojure and contrib for your initial learning as it will better match the book. When 1.2 is released stable I'm sure there will be a document written that explains the differences. I really wish the 1.1.0 release builds were more prominently linked on the clojure.org website, but you can download them here: http://build.clojure.org/releases/org/clojure/clojure/1.1.0/clojure-1.1.0.jar http://build.clojure.org/releases/org/clojure/clojure-contrib/1.1.0/clojure-contrib-1.1.0.jar Hope that helps, Alex -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Slides for short (45 minutes) presentation of clojure for java devs
Hello, I've consulted a lot of already made presentations of clojure. They are great, but I guess they may not suit my needs because it seems to me that either: * they are more 1 1/2 to 2 hours talks than 45 minutes * they assume the "public" will not be relunctant to some terms like "Lisp", "Functional Programming" and directly present these as advantages My goal is to raise interest into clojure in the mind of a public of people having used java for a long time. They may have Scala already in their "radar", but not clojure, or may have seen it and immediately dismissed it for what seemed to them good reasons (mainly aversion for lisp syntax), though we all know this is not true after the "normal" adaptation period. Say this presentation could be the presentation that leads people, at its end, asking you for giving all those great other presentations already available that I mentioned before ... Any references I missed that already solve my problem ? :-) Thanks in advance, -- Laurent -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Arguments for < and > et al
The built-in Java comparison operators don't honor Comparable either. In Clojure, it's about keeping (pure number) math fast. If you are doing any nontrivial date work, I recommend you look at clj- time (http://github.com/clj-sys/clj-time), a Clojure wrapper for Joda Time. Then, if you really want "<" and ">" to work, you can define them in your own namespace to wrap clj-time's "after?" and "before?". Stu I've been writing a program that requires the use of java.util.Calendar and its descendent java.util.GregorianCalendar. One thing I'd hoped to do was compare two Calendar objects with <, but the compiler complained that the arguments to < didn't inherit from Number which was a surprise to me because Calendar does inherit from java.lang.Comparable which in java land would be sufficient to enable it to be compared with other members of its class using the built in java comparison operators. Since I know that clojure has other operations that deal with comparable, I assume this is a conscious decision, but I question why it should be so. Regards, Bill -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
Thanks for the reply Alex, I thought of 2 try blocks, but seems over engineering doesn't it ? I actually need to open 2 connections simultaneously, which would amount to 3 nested try blocks. The whole code gets cluttered with all these try finally (and one catch) statements. (try (let [conn1 (API1/getConnection ..)] (try (let [conn2 (API2/getConnection ..)] (try ( ... Do something with conn1 conn2 ) (finally (API2/closeConnection conn2 (finally (API1/closeConnection conn1 (catch Exception ex (.printStackTrace ex))) The macro solution looks good. But with 2 different APIs for 2 connections, I would need to write 2 macros right? (defmacro with-api1-connection [conn-sym arg1 arg2 & body] `(let [~conn-sym (API1/getConnection ~arg1 ~arg2)] (try ~...@body (finally (API1/closeConnection ~conn-sym) (defmacro with-api2-connection [conn-sym arg1 arg2 arg3 & body] `(let [~conn-sym (API2/getConnection ~arg1 ~arg2 ~arg3)] (try ~...@body (finally (API2/closeConnection ~conn-sym) Also coming back to the original requirement, wanted to know what are the problems with providing support (somehow) for something like - (try (let [conn1 (API1/getConnection ..) conn2 (API2/getConnection ..)] ()) (catch ..) (finally (if conn1 (API1/closeConnection conn1)) (if conn2 (API2/closeConnection conn2 Coming from Java, this would be implemented as - Connection1 conn1 = null; Connection2 conn2 = null; try { conn1 = API1.getConnection ..; conn2 = API2.getConnection ..; ... } catch (){} finally { if (conn1 != null) API1.closeConnection(conn1); if (conn2 != null) API2.closeConnection(conn2); } I agree that this code doesn't look good from a purist pov, but any issues besides that? - Thanks! On Apr 21, 4:58 pm, Alex Osborne wrote: > ka writes: > > How can I do something like ... > > > (try > > (let [conn (API/getConnection ..)] > > ()) > > (catch ..) > > (finally (if conn (API/closeConnection conn > > > Problem is that conn is unavailable in the finally context. > > Why not just have two try blocks? > > (try > (let [conn (API/getConnection ..)] > (try > () > (finally (API/closeConnection conn > (catch ...)) > > For these sorts of things I usually try to use with-open, or if > with-open is not applicable do my own similar macro: > > (defmacro with-api-connection [conn-sym arg1 arg2 & body] > `(let [~conn-sym (API/getConnection ~arg1 ~arg2)] > (try > ~...@body > (finally (API/closeConnection ~conn-sym) > > So then you never forget to close the connection: > > (try > (with-api-connection conn ... > (... do something with conn ...)) > (catch ...)) > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: duck-streams missing from clojure-contrib.jar file
On 2010 Apr 21, at 8:11 AM, Alex Osborne wrote: I suggest you use the stable 1.1 releases of both Clojure and contrib for your initial learning as it will better match the book. When 1.2 is released stable I'm sure there will be a document written that explains the differences. That isn't as helpful as you might think. (I'm using 1.1, as conveniently provided by macports.) Nothing that I can find on either clojure.org or the contrib site http://richhickey.github.com/clojure-contrib/ says what version it is/applies-to. How would I know if I'm using the stable 1.1 release that I need to replace clojure.contrib.seq with clojure.contrib.seq-utils, or clojure.contrib.io with clojure.contrib.duck-stream? http://richhickey.github.com/clojure-contrib/io-api.html doesn't say: This document applies to 1.2 (pending), for 1.1 or older see: nor: This document applies to 1.2 (pending), it was renamed from clojure.contrib.duck-stream --Doug -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
On Wed, Apr 21, 2010 at 9:06 AM, ka wrote: > Connection1 conn1 = null; > Connection2 conn2 = null; > try { > conn1 = API1.getConnection ..; > conn2 = API2.getConnection ..; > ... > } You can't do that without using atoms or something, because you're assigning to conn1 and conn2 twice. That's not legal in Clojure because what "let" gives you aren't variables, but local constants. One solution would be to add a new construct to the language: (try-let [bindings] (body) (catch...) (finally...)) where any exception during evaluation of the [bindings] would be caught just as if it happened inside the body, and of course the bound variables would be visible to both the catch blocks and the finally block. It could be implemented as a macro that duplicated the catch/finally blocks within and outside a let... -- Mark J. Reed -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: duck-streams missing from clojure-contrib.jar file
The second level header tells you the branch (e.g. master). On the left hand side is a list of branches (so you can click on e.g. 1.1.x). Some ways I see this might be better: (1) make clear what master currently equals (right now it is 1.2 alpha) (2) highlight the branch info more with css (3) push the branch info into the top-level header (and page title) (4) The overview section for c.c.io could tell about the lineage back to 1.1. Which of these (or what else?) would have helped you the most? Stu On 2010 Apr 21, at 8:11 AM, Alex Osborne wrote: I suggest you use the stable 1.1 releases of both Clojure and contrib for your initial learning as it will better match the book. When 1.2 is released stable I'm sure there will be a document written that explains the differences. That isn't as helpful as you might think. (I'm using 1.1, as conveniently provided by macports.) Nothing that I can find on either clojure.org or the contrib site http://richhickey.github.com/clojure-contrib/ says what version it is/applies-to. How would I know if I'm using the stable 1.1 release that I need to replace clojure.contrib.seq with clojure.contrib.seq-utils, or clojure.contrib.io with clojure.contrib.duck-stream? http://richhickey.github.com/clojure-contrib/io-api.html doesn't say: This document applies to 1.2 (pending), for 1.1 or older see: nor: This document applies to 1.2 (pending), it was renamed from clojure.contrib.duck-stream --Doug -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
Hi, Something I don't understand: if the call to (API/getConnection ...) fails, there is nothing to close, right ? So for the problem of ensuring that any open connection is always closed, the following pattern seems enough: (try (let [conn (API/getConnection ..)] XXX) (finally (API/closeConnection conn))) In XXX you can do your business job, maybe catching exceptions, etc., but that is not the same intent as ensuring pairs of open/close calls in any case. Smart java frameworks such as SpringFramework do the exact same thing by using Interface callbacks encapsulating the XXX "real interesting code". The less verbose way of doing this is clojure's with-open macro. Though you would have, as Alex pointed out, to create your own variant of with-open to accomodate your particular API for closing the connection. Or, if you use master, you could write the protocol-aware version of with-open :-) 2010/4/21 ka : > Hi, > > I'm using an API to connect to a server which does not provide > constructors, just static methods to get & close connections. > > How can I do something like ... > > (try > (let [conn (API/getConnection ..)] > ()) > (catch ..) > (finally (if conn (API/closeConnection conn > > Problem is that conn is unavailable in the finally context. > > Is there any easy workaround which doesn't involve defing a global > conn. > > - Thanks > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
Oh, also see the source code for with-open : http://github.com/richhickey/clojure/blob/master/src/clj/clojure/core.clj#L2542 and also note that it allows you to declare bindings for opening connections in sequence, and will take care of closing them in the reverse order. And to answer your question about writing 2 macros if you have different APIs, no no : * either use protocols if you work on the master branch * either use multimethods that is, use polymorphism :-) 2010/4/21 Laurent PETIT : > Hi, > > Something I don't understand: if the call to (API/getConnection ...) > fails, there is nothing to close, right ? > > So for the problem of ensuring that any open connection is always > closed, the following pattern seems enough: > > (try > (let [conn (API/getConnection ..)] > XXX) > (finally (API/closeConnection conn))) > > In XXX you can do your business job, maybe catching exceptions, etc., > but that is not the same intent as ensuring pairs of open/close calls > in any case. > > Smart java frameworks such as SpringFramework do the exact same thing > by using Interface callbacks encapsulating the XXX "real interesting > code". > > The less verbose way of doing this is clojure's with-open macro. > Though you would have, as Alex pointed out, to create your own variant > of with-open to accomodate your particular API for closing the > connection. > > Or, if you use master, you could write the protocol-aware version of > with-open :-) > > > 2010/4/21 ka : >> Hi, >> >> I'm using an API to connect to a server which does not provide >> constructors, just static methods to get & close connections. >> >> How can I do something like ... >> >> (try >> (let [conn (API/getConnection ..)] >> ()) >> (catch ..) >> (finally (if conn (API/closeConnection conn >> >> Problem is that conn is unavailable in the finally context. >> >> Is there any easy workaround which doesn't involve defing a global >> conn. >> >> - Thanks >> >> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clojure@googlegroups.com >> Note that posts from new members are moderated - please be patient with your >> first post. >> To unsubscribe from this group, send email to >> clojure+unsubscr...@googlegroups.com >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
On Wed, Apr 21, 2010 at 9:37 AM, Laurent PETIT wrote: > Hi, > > Something I don't understand: if the call to (API/getConnection ...) > fails, there is nothing to close, right ? > > So for the problem of ensuring that any open connection is always > closed, the following pattern seems enough: > > (try > (let [conn (API/getConnection ..)] > XXX) > (finally (API/closeConnection conn))) > That would be great, but it doesn't work, because "conn" doesn't exist any more by the time you get to the finally block. That's the problem being addressed in this thread. So you can do this: (let [conn (API/getConnection ...)] (try XXX (finally (API/closeConnection conn But then any exception thrown by API/getConnection is not caught. So you have to do this: (try (let [conn (API/getConnection ...)] (try XXX (finally (API/closeConnection conn (catch ...)) But that still won't work if the catch block also needs access to "conn". So you wind up with something like this: (try (let [conn (API/getConnection ...)] (try XXX (catch ExceptionAfterConnect x (do-something-with conn)) (finally (API/closeConnection conn (catch .ExceptionDuringConnect x (do-something-without-conn -- Mark J. Reed -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
2010/4/21 Mark J. Reed : > On Wed, Apr 21, 2010 at 9:37 AM, Laurent PETIT > wrote: >> >> Hi, >> >> Something I don't understand: if the call to (API/getConnection ...) >> fails, there is nothing to close, right ? >> >> So for the problem of ensuring that any open connection is always >> closed, the following pattern seems enough: >> >> (try >> (let [conn (API/getConnection ..)] >> XXX) >> (finally (API/closeConnection conn))) Of course, My code was wrong, and I meant (let [conn (API/getConnection ..)] (try XXX (finally (API/closeConnection conn))) And really, catching exceptions thrown by API/getConnection is not in the problem domain of ensuring balanced pairs of opened/closed connections, e.g. should be outside the abstraction you put in place for handling this (e.g. with-open). Ensuring that opened connections are closed is a resource (I/O) management problem. Handling the case where you were not able to open a connection is an application problem. You might place the try/catch right around the let, have a global handling very high in the call stack, or even have no try/catch at all. HTH, -- Laurent > > That would be great, but it doesn't work, because "conn" doesn't exist any > more by the time you get to the finally block. That's the problem being > addressed in this thread. > So you can do this: > (let [conn (API/getConnection ...)] > (try > XXX > (finally (API/closeConnection conn > But then any exception thrown by API/getConnection is not caught. > > So you have to do this: > (try > (let [conn (API/getConnection ...)] > (try > XXX > (finally (API/closeConnection conn > (catch ...)) > But that still won't work if the catch block also needs access to "conn". > So you wind up with something like this: > (try > (let [conn (API/getConnection ...)] > (try > XXX > (catch ExceptionAfterConnect x (do-something-with conn)) > (finally (API/closeConnection conn > (catch .ExceptionDuringConnect x (do-something-without-conn > -- > Mark J. Reed > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
ka writes: > The whole code gets cluttered with all these try finally (and one > catch) statements. > > (try > (let [conn1 (API1/getConnection ..)] > (try > (let [conn2 (API2/getConnection ..)] > (try > ( ... Do something with conn1 conn2 ) > (finally > (API2/closeConnection conn2 > (finally > (API1/closeConnection conn1 > (catch Exception ex (.printStackTrace ex))) I guess the main difference in this compared to your java example is the levels of nesting. This may look messy but it's semantically exactly what you're trying to express. > The macro solution looks good. But with 2 different APIs for 2 > connections, I would need to write 2 macros right? > > (defmacro with-api1-connection [conn-sym arg1 arg2 & body] > `(let [~conn-sym (API1/getConnection ~arg1 ~arg2)] > (try > ~...@body > (finally (API1/closeConnection ~conn-sym) > > (defmacro with-api2-connection [conn-sym arg1 arg2 arg3 & body] > `(let [~conn-sym (API2/getConnection ~arg1 ~arg2 ~arg3)] > (try > ~...@body > (finally (API2/closeConnection ~conn-sym) You could make things more general: (with-cleanup [conn1 (API1/getConnection ...) API1/closeConnection conn2 (API2/openConnection ...) #(.disconnect %)] ...) I'll leave implementation as an exercise, it's not much more complicated than the previous ones, the main trick would just be to make the macro recursive, have it expand into: (let [conn1 (API1/getConnection ...)] (try (with-cleanup [conn2 (API2/openConnection ...) #(.disconnect %)] ...) (finally (API1/closeConnection conn1 I'd probably start with a signature like this: (defmacro with-cleanup [[sym create cleanup & more] & body] ...) Take a look at the source for with-open if you get stuck. > Coming from Java, this would be implemented as - > > Connection1 conn1 = null; > Connection2 conn2 = null; > try { > conn1 = API1.getConnection ..; > conn2 = API2.getConnection ..; > ... > } > catch (){} > finally { > if (conn1 != null) > API1.closeConnection(conn1); > if (conn2 != null) > API2.closeConnection(conn2); > } > > I agree that this code doesn't look good from a purist pov, but any > issues besides that? The problem here is that this breaks lexical scope, conn1 and conn2 aren't defined outside their let block. The Java example dodges this with mutation. Python/Ruby/JavaScript etc dodge it by having special scoping rules: variables are scoped to functions rather than the enclosing block. Clojure's opinion, as I understand it, is that it's not worthwhile introducing mutation or special scoping rules simply to avoid some nesting, when we have perfectly good tools (macros) for doing purely syntactic transformations and removing boilerplate. There's nothing semantically wrong with nesting, it's just harder to read. The Clojure idiom for reducing nesting is usually to use a macro like ->, ->> or with-open to flatten it. In this case those aren't applicable, so I suggest defining your own. I'm not sure I phrased that clearly, please let me know if I'm not making sense. :-) Alex -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
On Wednesday 21 April 2010 15:06:40 ka wrote: Hi! > The macro solution looks good. But with 2 different APIs for 2 > connections, I would need to write 2 macros right? No, not really. You could also make the symbols for the API class an additional arg to the macro, like: (defmacro with-api-connection [conn-sym api arg1 arg2 & body] `(let [~conn-sym (. ~api getConnection ~arg1 ~arg2)] (try ~...@body (finally (. ~api closeConnection ~conn-sym) but then the macre application would be longer. (with-api-connection [c API1 "localhost" 12345] (with-api-connection [c2 API2 "141.55.22.1" 13321] (do-stuff-with c c2)) (do-stuff-with c)) Bye, Tassilo -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: duck-streams missing from clojure-contrib.jar file
Stuart Halloway writes: > The second level header tells you the branch (e.g. master). On the > left hand side is a list of branches (so you can click on e.g. 1.1.x). > > Some ways I see this might be better: > > (1) make clear what master currently equals (right now it is 1.2 alpha) > (2) highlight the branch info more with css > (3) push the branch info into the top-level header (and page title) > (4) The overview section for c.c.io could tell about the lineage back > to 1.1. I think it might also help to make the stable versions the default view. I think people new to the language should really be guided to using the stable releases and documentation rather than snapshots, as the snapshots may well be in flux and cause lots of confusion. People choosing to use the bleeding edge git snapshots will know what the branches are and can specify the one they want. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: duck-streams missing from clojure-contrib.jar file
2010/4/21 Alex Osborne : > Stuart Halloway writes: > >> The second level header tells you the branch (e.g. master). On the >> left hand side is a list of branches (so you can click on e.g. 1.1.x). >> >> Some ways I see this might be better: >> >> (1) make clear what master currently equals (right now it is 1.2 alpha) >> (2) highlight the branch info more with css >> (3) push the branch info into the top-level header (and page title) >> (4) The overview section for c.c.io could tell about the lineage back >> to 1.1. > > I think it might also help to make the stable versions the default > view. I think people new to the language should really be guided to > using the stable releases and documentation rather than snapshots, as > the snapshots may well be in flux and cause lots of confusion. > People choosing to use the bleeding edge git snapshots will know what > the branches are and can specify the one they want. #(swap! % inc) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
Thanks all for replies. Laurent, Alex you guys are right, the problem is only with aesthetics of nesting / boilerplate. The nesting implementation semantically expresses exactly what is required. The with-cleanup macro seems really neat. Guess I'll learn macros first and try to implement one. One more interesting perspective to exceptional handling is the way Perl 6 is doing it - http://feather.perl6.nl/syn/S04.html#Exception_handlers See this - { my $s = ''; die 3; CATCH { when 1 {$s ~= 'a';} when 2 {$s ~= 'b';} when 3 {$s ~= 'c';} when 4 {$s ~= 'd';} default {$s ~= 'z';} } is $s, 'c', 'Caught number'; }; Thanks! On Apr 21, 7:05 pm, Alex Osborne wrote: > ka writes: > > The whole code gets cluttered with all these try finally (and one > > catch) statements. > > > (try > > (let [conn1 (API1/getConnection ..)] > > (try > > (let [conn2 (API2/getConnection ..)] > > (try > > ( ... Do something with conn1 conn2 ) > > (finally > > (API2/closeConnection conn2 > > (finally > > (API1/closeConnection conn1 > > (catch Exception ex (.printStackTrace ex))) > > I guess the main difference in this compared to your java example is the > levels of nesting. This may look messy but it's semantically exactly > what you're trying to express. > > > The macro solution looks good. But with 2 different APIs for 2 > > connections, I would need to write 2 macros right? > > > (defmacro with-api1-connection [conn-sym arg1 arg2 & body] > > `(let [~conn-sym (API1/getConnection ~arg1 ~arg2)] > > (try > > ~...@body > > (finally (API1/closeConnection ~conn-sym) > > > (defmacro with-api2-connection [conn-sym arg1 arg2 arg3 & body] > > `(let [~conn-sym (API2/getConnection ~arg1 ~arg2 ~arg3)] > > (try > > ~...@body > > (finally (API2/closeConnection ~conn-sym) > > You could make things more general: > > (with-cleanup [conn1 (API1/getConnection ...) API1/closeConnection > conn2 (API2/openConnection ...) #(.disconnect %)] > ...) > > I'll leave implementation as an exercise, it's not much more complicated > than the previous ones, the main trick would just be to make the macro > recursive, have it expand into: > > (let [conn1 (API1/getConnection ...)] > (try > (with-cleanup [conn2 (API2/openConnection ...) #(.disconnect %)] > ...) > (finally > (API1/closeConnection conn1 > > I'd probably start with a signature like this: > > (defmacro with-cleanup [[sym create cleanup & more] & body] > ...) > > Take a look at the source for with-open if you get stuck. > > > > > Coming from Java, this would be implemented as - > > > Connection1 conn1 = null; > > Connection2 conn2 = null; > > try { > > conn1 = API1.getConnection ..; > > conn2 = API2.getConnection ..; > > ... > > } > > catch (){} > > finally { > > if (conn1 != null) > > API1.closeConnection(conn1); > > if (conn2 != null) > > API2.closeConnection(conn2); > > } > > > I agree that this code doesn't look good from a purist pov, but any > > issues besides that? > > The problem here is that this breaks lexical scope, conn1 and > conn2 aren't defined outside their let block. The Java example dodges > this with mutation. Python/Ruby/JavaScript etc dodge it by having > special scoping rules: variables are scoped to functions rather than the > enclosing block. > > Clojure's opinion, as I understand it, is that it's not worthwhile > introducing mutation or special scoping rules simply to avoid some > nesting, when we have perfectly good tools (macros) for doing purely > syntactic transformations and removing boilerplate. > > There's nothing semantically wrong with nesting, it's just harder > to read. The Clojure idiom for reducing nesting is usually to use a > macro like ->, ->> or with-open to flatten it. In this case those > aren't applicable, so I suggest defining your own. > > I'm not sure I phrased that clearly, please let me know if I'm not > making sense. :-) > > Alex > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Try + finally question
Hi, I don't know for sure, but it seems to me that perl 6 way of "writing" exception handling is just a syntactic difference. For an interesting shift in the possibilities of exception handling/recovery, have a look at how Common Lisp does this with conditions/restart : http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html Which has been ported to clojure by chouser: http://richhickey.github.com/clojure-contrib/error-kit-api.html In a nutshell, with this you can simulate handlers placed higher in the call stack, but those handlers could compute a "recovery value" that would replace the value returned by the innermost from which the exception originated (though this is totally off topic with your original post :-) ). 2010/4/21 ka : > Thanks all for replies. > > Laurent, Alex you guys are right, the problem is only with aesthetics > of nesting / boilerplate. The nesting implementation semantically > expresses exactly what is required. > > The with-cleanup macro seems really neat. Guess I'll learn macros > first and try to implement one. > > One more interesting perspective to exceptional handling is the way > Perl 6 is doing it - http://feather.perl6.nl/syn/S04.html#Exception_handlers > > See this - > > { > my $s = ''; > die 3; > CATCH { > when 1 {$s ~= 'a';} > when 2 {$s ~= 'b';} > when 3 {$s ~= 'c';} > when 4 {$s ~= 'd';} > default {$s ~= 'z';} > } > > is $s, 'c', 'Caught number'; > }; > > Thanks! > > On Apr 21, 7:05 pm, Alex Osborne wrote: >> ka writes: >> > The whole code gets cluttered with all these try finally (and one >> > catch) statements. >> >> > (try >> > (let [conn1 (API1/getConnection ..)] >> > (try >> > (let [conn2 (API2/getConnection ..)] >> > (try >> > ( ... Do something with conn1 conn2 ) >> > (finally >> > (API2/closeConnection conn2 >> > (finally >> > (API1/closeConnection conn1 >> > (catch Exception ex (.printStackTrace ex))) >> >> I guess the main difference in this compared to your java example is the >> levels of nesting. This may look messy but it's semantically exactly >> what you're trying to express. >> >> > The macro solution looks good. But with 2 different APIs for 2 >> > connections, I would need to write 2 macros right? >> >> > (defmacro with-api1-connection [conn-sym arg1 arg2 & body] >> > `(let [~conn-sym (API1/getConnection ~arg1 ~arg2)] >> > (try >> > ~...@body >> > (finally (API1/closeConnection ~conn-sym) >> >> > (defmacro with-api2-connection [conn-sym arg1 arg2 arg3 & body] >> > `(let [~conn-sym (API2/getConnection ~arg1 ~arg2 ~arg3)] >> > (try >> > ~...@body >> > (finally (API2/closeConnection ~conn-sym) >> >> You could make things more general: >> >> (with-cleanup [conn1 (API1/getConnection ...) API1/closeConnection >> conn2 (API2/openConnection ...) #(.disconnect %)] >> ...) >> >> I'll leave implementation as an exercise, it's not much more complicated >> than the previous ones, the main trick would just be to make the macro >> recursive, have it expand into: >> >> (let [conn1 (API1/getConnection ...)] >> (try >> (with-cleanup [conn2 (API2/openConnection ...) #(.disconnect %)] >> ...) >> (finally >> (API1/closeConnection conn1 >> >> I'd probably start with a signature like this: >> >> (defmacro with-cleanup [[sym create cleanup & more] & body] >> ...) >> >> Take a look at the source for with-open if you get stuck. >> >> >> >> > Coming from Java, this would be implemented as - >> >> > Connection1 conn1 = null; >> > Connection2 conn2 = null; >> > try { >> > conn1 = API1.getConnection ..; >> > conn2 = API2.getConnection ..; >> > ... >> > } >> > catch (){} >> > finally { >> > if (conn1 != null) >> > API1.closeConnection(conn1); >> > if (conn2 != null) >> > API2.closeConnection(conn2); >> > } >> >> > I agree that this code doesn't look good from a purist pov, but any >> > issues besides that? >> >> The problem here is that this breaks lexical scope, conn1 and >> conn2 aren't defined outside their let block. The Java example dodges >> this with mutation. Python/Ruby/JavaScript etc dodge it by having >> special scoping rules: variables are scoped to functions rather than the >> enclosing block. >> >> Clojure's opinion, as I understand it, is that it's not worthwhile >> introducing mutation or special scoping rules simply to avoid some >> nesting, when we have perfectly good tools (macros) for doing purely >> syntactic transformations and removing boilerplate. >> >> There's nothing semantically wrong with nesting, it's just harder >> to read. The Clojure idiom for reducing nesting is usually to use a >> macro like ->, ->> or with-open to flatten it. In this case those >> aren't applicable, so I suggest defining your own. >> >> I'm not sure I phrased that
Re: Try + finally question
The main thing about Perl6 in this case is that the catch/finally blocks are inside the same scope as the try. But that's true in Clojure as well! The difference is that Clojure's try is not itself a lexical binding scope; you have to wrap one around it or within it via let. That's why I thought a combination of try and let would be useful, if only as syntactic sugar. On Wed, Apr 21, 2010 at 10:43 AM, ka wrote: > Thanks all for replies. > > Laurent, Alex you guys are right, the problem is only with aesthetics > of nesting / boilerplate. The nesting implementation semantically > expresses exactly what is required. > > The with-cleanup macro seems really neat. Guess I'll learn macros > first and try to implement one. > > One more interesting perspective to exceptional handling is the way > Perl 6 is doing it - > http://feather.perl6.nl/syn/S04.html#Exception_handlers > > See this - > > { >my $s = ''; >die 3; >CATCH { >when 1 {$s ~= 'a';} >when 2 {$s ~= 'b';} >when 3 {$s ~= 'c';} >when 4 {$s ~= 'd';} >default {$s ~= 'z';} >} > >is $s, 'c', 'Caught number'; > }; > > Thanks! > > On Apr 21, 7:05 pm, Alex Osborne wrote: > > ka writes: > > > The whole code gets cluttered with all these try finally (and one > > > catch) statements. > > > > > (try > > > (let [conn1 (API1/getConnection ..)] > > > (try > > > (let [conn2 (API2/getConnection ..)] > > > (try > > > ( ... Do something with conn1 conn2 ) > > > (finally > > > (API2/closeConnection conn2 > > > (finally > > > (API1/closeConnection conn1 > > > (catch Exception ex (.printStackTrace ex))) > > > > I guess the main difference in this compared to your java example is the > > levels of nesting. This may look messy but it's semantically exactly > > what you're trying to express. > > > > > The macro solution looks good. But with 2 different APIs for 2 > > > connections, I would need to write 2 macros right? > > > > > (defmacro with-api1-connection [conn-sym arg1 arg2 & body] > > > `(let [~conn-sym (API1/getConnection ~arg1 ~arg2)] > > > (try > > > ~...@body > > > (finally (API1/closeConnection ~conn-sym) > > > > > (defmacro with-api2-connection [conn-sym arg1 arg2 arg3 & body] > > > `(let [~conn-sym (API2/getConnection ~arg1 ~arg2 ~arg3)] > > > (try > > > ~...@body > > > (finally (API2/closeConnection ~conn-sym) > > > > You could make things more general: > > > > (with-cleanup [conn1 (API1/getConnection ...) API1/closeConnection > >conn2 (API2/openConnection ...) #(.disconnect %)] > > ...) > > > > I'll leave implementation as an exercise, it's not much more complicated > > than the previous ones, the main trick would just be to make the macro > > recursive, have it expand into: > > > > (let [conn1 (API1/getConnection ...)] > > (try > > (with-cleanup [conn2 (API2/openConnection ...) #(.disconnect %)] > > ...) > > (finally > > (API1/closeConnection conn1 > > > > I'd probably start with a signature like this: > > > > (defmacro with-cleanup [[sym create cleanup & more] & body] > > ...) > > > > Take a look at the source for with-open if you get stuck. > > > > > > > > > Coming from Java, this would be implemented as - > > > > > Connection1 conn1 = null; > > > Connection2 conn2 = null; > > > try { > > > conn1 = API1.getConnection ..; > > > conn2 = API2.getConnection ..; > > > ... > > > } > > > catch (){} > > > finally { > > > if (conn1 != null) > > > API1.closeConnection(conn1); > > > if (conn2 != null) > > > API2.closeConnection(conn2); > > > } > > > > > I agree that this code doesn't look good from a purist pov, but any > > > issues besides that? > > > > The problem here is that this breaks lexical scope, conn1 and > > conn2 aren't defined outside their let block. The Java example dodges > > this with mutation. Python/Ruby/JavaScript etc dodge it by having > > special scoping rules: variables are scoped to functions rather than the > > enclosing block. > > > > Clojure's opinion, as I understand it, is that it's not worthwhile > > introducing mutation or special scoping rules simply to avoid some > > nesting, when we have perfectly good tools (macros) for doing purely > > syntactic transformations and removing boilerplate. > > > > There's nothing semantically wrong with nesting, it's just harder > > to read. The Clojure idiom for reducing nesting is usually to use a > > macro like ->, ->> or with-open to flatten it. In this case those > > aren't applicable, so I suggest defining your own. > > > > I'm not sure I phrased that clearly, please let me know if I'm not > > making sense. :-) > > > > Alex > > > > -- > > You received this message because you are subscribed to the Google > > Groups "Clojure" group. > > To post to this group, send email to clojure@googlegroups.com > > Note
Missing fns: rotate & rotate-while
Hey everyone, I've had to code these guys up a few times: (defn rotate "Take a collection and left rotates it n steps. If n is negative, the collection is rotated right. Executes in O(n) time." [n coll] (let [c (count coll)] (take c (drop (mod n c) (cycle coll) (defn rotate-while "Rotates a collection left while (pred item) is true. Will return a unrotated sequence if (pred item) is never true. Executes in O(n) time." [pred coll] (let [head (drop-while pred coll)] (take (count coll) (concat head coll Have other people had this problem? -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Coordinated, asynchronous modification of state?
Hi All, This e-mail is the product of some musing about refs, agents, and atoms. I would like to offer some thoughts on a possible fourth reference type that allows coordinated, asynchronous modification of state. I would greatly appreciate comments from the community. Maybe some of these ideas have already been discussed on the list or incorporated into development, in which case I'm sorry for repeating what is already known---and please point me in the right direction so I can read more. I hope the ideas are not too far off base, but please let me know if you think they are. Let me start at the beginning. In Clojure, we have standard reference types for: * uncoordinated, synchronous state change, * coordinated, synchronous state change, * uncoordinated, asynchronous state change. Most Clojure users are familiar with the following diagram expressing the reference type taxonomy. (The ASCII diagrams in this e-mail are best viewed in a fixed-width font.) | Synchronous | Asynchronous --+--+- Uncoordinated | Atoms| Agents Coordinated | Refs | It occurred to me recently that there is no built-in reference type for the final quadrant: coordinated, asynchronous change. There is no reference type, in other words, allowing one to write a "doasync" block similar to a dosync block: (doasync ;short for do asynchronously (send a inc) (send b inc)) causing a and b to change together atomically in the background. I thought to myself that it would be nice to have this ability in some applications, especially simulation, artificial life, and agent-based modeling. It allows one thread to effect coordinated change in other threads while getting on with its own work. I pondered more and realized that, although there is no built-in reference type for this purpose, one can make a first stab at the same effect using a combination of futures and refs: (future (dosync (alter a inc) (alter b inc))) The future wraps the atomic transaction and causes it to take place in a background thread. This solution satisfied me for a day or two. Upon some more thought, however, I realized that combining refs with futures is a recipe for livelock disaster. Here is why. In a massively concurrent program with heavy asynchronous state change, it is unlikely that any one ref will stay the same for very long. The kind of coordinated change offered by a ref transaction is unlikely to be successful in this kind of constantly-changing environment, because the values of the refs are constantly being changed out from under the transaction attempts. Consider the following illustration, in which I try to modify a ref at the same time that it is being changed continually from another thread: begin example (def a (ref 1)) ; the code for start-frequent-changes is at ; http://gist.github.com/373143 (start-frequent-changes a) ; this code will never print its message (let [done? (agent nil)] (future (dosync (alter a (fn negate [val] (Thread/sleep 300) (- val))) ; negate is a long-running function of its argument (send done? (fn [_] (println "Done!")) end example The principle illustrated by this example is the following: when one or more other threads are changing a ref, a computationally expensive transaction on that ref is likely to encounter livelock. The more expensive the transaction and the more frequent the changes, the less likely it is that the transaction will ever go through. It will retry over and over, consuming resources and potentially retrying forever. Rich introduced ensure in part to try to mitigate this problem. Livelock can be avoided in the example above by placing a simple "(ensure a)" call at the beginning of the dosync block. Ensure ensures that the transaction holds "write permissions" on the ref during the transaction, so that other threads cannot modify it. However, the combination of futures, refs, and ensure is not a terribly good solution to coordinated asynchronicity, either, because it has a problem of its own: The order in which futures are executed is not deterministic. Race conditions will occur, and this is a big problem when dealing with state. To illustrate this, suppose one has three refs, a, b, and c. (In a real scenario, instead of just three refs one might have three groups of 20 refs, but three refs is enough to illustrate.) One wants to complete three asynchronous transactions on these refs in the following order: first, modify a, then modify both a and b, then modify both a and c. The problem is this: There is no way, using futures, refs, and ensure, to guarantee that the three asynchronous transactions will happen in the order one intends. Running the following code will usually print 3, but sometimes it will print 2, because there is a race condition affecting the second and third futures. begin example ;;;
Re: Missing fns: rotate & rotate-while
On 21 April 2010 17:23, Sean Devlin wrote: > I've had to code these guys up a few times: Nice functions! I'd replace "collection" with "sequence" in the docstrings, though. (And rename the args accordingly.) You can also rewrite rotate as (defn rotate [n s] (lazy-cat (drop n s) (take n s))) which has the built-in assumption that n doesn't exceed the length of s, but won't force more than (inc n) elements of s before producing the first item of the result. (Additional forcing might happen due to chunking issues, of course.) As a final remark, I believe that rotate takes constant time to execute, followed by O(n) time to produce the first element. This is petty nitpicking, of course. ;-) Sincerely, Michał -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Documentation (was: Re: duck-streams missing from clojure-contrib.jar file)
On 2010 Apr 21, at 9:31 AM, Stuart Halloway wrote: The second level header tells you the branch (e.g. master). On the left hand side is a list of branches (so you can click on e.g. 1.1.x). Wow, that is quite subtle. As you click into contrib from clojure.org it isn't very noticeable. It also isn't something you notice if you are, for example, clicking through from the unversioned clojure.org pages. An example at random: Start at: http://clojure.org/macros then click on the lazy-cat link, which takes you to: http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/ lazy-cat and start browsing. With your focus down 'into' that page you have no idea that you've jumped into versioned information. If you start as a beginner, as I did, the stuff on clojure.org is not versioned (there is no master/1.1.x link in the side bar) and so having version info appear only in contrib pages is not easy to notice, particularly if you get there via links from the main page. Some ways I see this might be better: (1) make clear what master currently equals (right now it is 1.2 alpha) That would help. Master is pretty generic. (2) highlight the branch info more with css Couldn't hurt, but it it'd be nice if showed in the page title too, the sidebars are lost when scrolling down into the various pages. (3) push the branch info into the top-level header (and page title) Yup. (4) The overview section for c.c.io could tell about the lineage back to 1.1. Not having been along for the ride since (nearly) the beginning, having those breadcrumbs would be helpful to me. Which of these (or what else?) would have helped you the most? I think having the default, as Alex Osburne suggested, be the stable release would have made my exploration of 1.1 a lot less painful. And along those lines, distinguishing between core and contrib is something that might be important to the maintainers, but not so much to the users. And, very less useful to newbies trying to get something useful done. Trying to figure out that spit is in a contrib library and slurp isn't? C'mon. I finally broke down and used google, and then when I saw a thread back in '08 about that, and it still isn't addressed? Really, easy file I/O is that unimportant to most clojure users? Having a unified and comprehensive index of functions/macros (annotated with core/contrib) would also go a long way to making the clojure documentation environment a lot more useful. Oh, and then there is the distinction between http://clojure.org/libraries and the contrib libraries. Yet another place to look? Great, I really don't have anything better to do than internalize these distinctions? (In case you can't tell, having burned -hours- of spare time trying to find my way around docs has been exceptionally frustrating.) At least for someone like me who is exploring on their own and isn't getting paid to make this work, having to lose my train of thought for 5-10 minutes while trying to figure out if something is core or contrib is hugely frustrating and demotivating. Then throw in a "wtf? why isn't this working in the stable release" only makes it more so when I'm looking at the wrong docs and didn't even know that there were versioned docs. If you want an example of the kind of structure that I do find helpful, look at docs.python.org. How many times on that page do you see that you're lookin at the 2.6 docs and that there are links to others? I'm not saying to make an exact clone, but I think it is fair, if I am going to complain about this, that I also provide, at least, an example of something that works and has worked well for years. (I come to clojure from Lisp and Python, not Java, so I don't have any Java documentation familiarity to compare/contrast). -Doug -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
You're right about changing the docstring to read ""sequence" I think the lazy-cat version looses the ability to rotate in reverse, which I've come to love from Ruby. Also, I have found use cases where I want to rotate a period longer than the sequence length. Thanks for the feedback, though. Sean On Apr 21, 11:37 am, Michał Marczyk wrote: > On 21 April 2010 17:23, Sean Devlin wrote: > > > I've had to code these guys up a few times: > > Nice functions! > > I'd replace "collection" with "sequence" in the docstrings, though. > (And rename the args accordingly.) > > You can also rewrite rotate as > > (defn rotate [n s] > (lazy-cat (drop n s) > (take n s))) > > which has the built-in assumption that n doesn't exceed the length of > s, but won't force more than (inc n) elements of s before producing > the first item of the result. (Additional forcing might happen due to > chunking issues, of course.) > > As a final remark, I believe that rotate takes constant time to > execute, followed by O(n) time to produce the first element. This is > petty nitpicking, of course. ;-) > > Sincerely, > Michał > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Coordinated, asynchronous modification of state?
Hi All, The moment one sends a post one starts thinking about it from a critical perspective. I think I may have grown so used to the idea that nothing in Clojure can deadlock that I completely overlooked the possibility of deadlock in the idea I proposed. If two serfs are the targets of two different transactions, and those transactions happen to enter the serfs' queues in different orders, the serfs will wait forever for each other to become free. Classic deadlock. So, this stands as a challenge: Is there any way to get coordinated, asynchronous, guaranteed-in-order modification of state? Or is it a pick-two situation? Thanks, Garth On Wed, Apr 21, 2010 at 11:29 AM, Garth Sheldon-Coulson wrote: > Hi All, > > This e-mail is the product of some musing about refs, agents, and atoms. I > would like to offer some thoughts on a possible fourth reference type that > allows coordinated, asynchronous modification of state. > > I would greatly appreciate comments from the community. Maybe some of these > ideas have already been discussed on the list or incorporated into > development, in which case I'm sorry for repeating what is already > known---and please point me in the right direction so I can read more. I > hope the ideas are not too far off base, but please let me know if you think > they are. > > Let me start at the beginning. In Clojure, we have standard reference types > for: > > * uncoordinated, synchronous state change, > * coordinated, synchronous state change, > * uncoordinated, asynchronous state change. > > Most Clojure users are familiar with the following diagram expressing the > reference type taxonomy. (The ASCII diagrams in this e-mail are best viewed > in a fixed-width font.) > > | Synchronous | Asynchronous > --+--+- > Uncoordinated | Atoms| Agents > Coordinated | Refs | > > It occurred to me recently that there is no built-in reference type for the > final quadrant: coordinated, asynchronous change. There is no reference > type, in other words, allowing one to write a "doasync" block similar to a > dosync block: > > (doasync ;short for do asynchronously > (send a inc) > (send b inc)) > > causing a and b to change together atomically in the background. I thought > to myself that it would be nice to have this ability in some applications, > especially simulation, artificial life, and agent-based modeling. It allows > one thread to effect coordinated change in other threads while getting on > with its own work. > > I pondered more and realized that, although there is no built-in reference > type for this purpose, one can make a first stab at the same effect using a > combination of futures and refs: > > (future > (dosync > (alter a inc) > (alter b inc))) > > The future wraps the atomic transaction and causes it to take place in a > background thread. > > This solution satisfied me for a day or two. Upon some more thought, > however, I realized that combining refs with futures is a recipe for > livelock disaster. Here is why. In a massively concurrent program with heavy > asynchronous state change, it is unlikely that any one ref will stay the > same for very long. The kind of coordinated change offered by a ref > transaction is unlikely to be successful in this kind of constantly-changing > environment, because the values of the refs are constantly being changed out > from under the transaction attempts. Consider the following illustration, in > which I try to modify a ref at the same time that it is being changed > continually from another thread: > > begin example > (def a (ref 1)) > > ; the code for start-frequent-changes is at > ; http://gist.github.com/373143 > (start-frequent-changes a) > > ; this code will never print its message > (let [done? (agent nil)] > (future > (dosync > (alter a (fn negate [val] (Thread/sleep 300) (- val))) > ; negate is a long-running function of its argument > (send done? (fn [_] (println "Done!")) > end example > > The principle illustrated by this example is the following: when one or > more other threads are changing a ref, a computationally expensive > transaction on that ref is likely to encounter livelock. The more expensive > the transaction and the more frequent the changes, the less likely it is > that the transaction will ever go through. It will retry over and over, > consuming resources and potentially retrying forever. > > Rich introduced ensure in part to try to mitigate this problem. Livelock > can be avoided in the example above by placing a simple "(ensure a)" call at > the beginning of the dosync block. Ensure ensures that the transaction holds > "write permissions" on the ref during the transaction, so that other threads > cannot modify it. > > However, the combination of futures, refs, and ensure is not a terribly > good solution to coordinated asynchronicity, either
Re: Missing fns: rotate & rotate-while
On 21 April 2010 17:46, Sean Devlin wrote: > I think the lazy-cat version looses the ability to rotate in reverse, > which I've come to love from Ruby. Also, I have found use cases where > I want to rotate a period longer than the sequence length. Right. I don't mind rotate being strict, actually, I'm just playing around and being silly: (defn rotate [n s] (if-let [remaining (and (not (neg? n)) (seq (drop n s)))] (lazy-cat remaining (take n s)) (let [c (count s)] (take c (drop (mod n c) (cycle s)) Seriously though, I'd vote for your original versions to go into c.c.seq. Sincerely, Michał -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: sharing multiple jogl opengl contexts in clojure
On Apr 20, 4:46 pm, Josh Stratton wrote: > But I can't seem to call createGLPbuffer w/o getting an exception. > Caused by: java.lang.IllegalArgumentException: No matching method: > createGLPbuffer This one is because the createGLPbuffer method is not static; you need to have created a GLDrawableFactory first using getFactory(): (.createGLPbuffer (GLDrawableFactory/getFactory (GLProfile/ getDefault)) nil nil 1 1 nil) The GLCapabilities argument needs to be set, otherwise you'll get a NullPointerException at this point. The simplest invocation I could come up with that returned a GLPbufferImpl was this: (let [profile (GLProfile/getDefault)] (.createGLPbuffer (GLDrawableFactory/getFactory profile) (GLCapabilities. profile) nil 1 1 nil)) You can take it from here with different profiles, capabilities, choosers etc. J PS I'm using Clojure 1.1 and JOGL 2.0. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
On Wed, Apr 21, 2010 at 8:46 AM, Sean Devlin wrote: > You're right about changing the docstring to read ""sequence" > > I think the lazy-cat version looses the ability to rotate in reverse, > which I've come to love from Ruby. Also, I have found use cases where > I want to rotate a period longer than the sequence length. > > Thanks for the feedback, though. > Sean The use of concatenation as opposed to cycle does not affect the ability to rotate in reverse or more than the sequence length provided you use mod to get the number in range first: (defn rotate [n s] (let [shift (mod n (count s))] (concat (drop shift s) (take shift s [could use lazy-cat instead of concat, but I doubt it's worthwhile here] -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
How do I destructure this?
Hi All - I am having a hard time destructuring a nested data structure. I am starting out with: {:tag :column, :attrs nil, :content [{:tag :name, :attrs nil, :content ["agecat"]} {:tag :value, :attrs nil, :content ["nil"]} {:tag :threshold, :attrs nil, :content ["0.05"]}]} and am looking to get: {:column "agecat", :value "nil", :threshold "0.05"} I genearlly 'get' the destructuring and it is very cool, but the highly nested aspect of this is throwing me off. Any thoughts would be most appreciated. Thanks Bassel -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
Hmmm... good point. Now that I think about it, cycle is an artifact of an early implementation. On Apr 21, 1:01 pm, Mark Engelberg wrote: > On Wed, Apr 21, 2010 at 8:46 AM, Sean Devlin wrote: > > You're right about changing the docstring to read ""sequence" > > > I think the lazy-cat version looses the ability to rotate in reverse, > > which I've come to love from Ruby. Also, I have found use cases where > > I want to rotate a period longer than the sequence length. > > > Thanks for the feedback, though. > > Sean > > The use of concatenation as opposed to cycle does not affect the > ability to rotate in reverse or more than the sequence length provided > you use mod to get the number in range first: > > (defn rotate [n s] > (let [shift (mod n (count s))] > (concat (drop shift s) > (take shift s > > [could use lazy-cat instead of concat, but I doubt it's worthwhile here] > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: How do I destructure this?
Hmmm... I'm not sure destructuring is possible here. Would it be easier to put an extractor fn in place? (defn extract [arg] (apply hash-map (map (juxt :tag :content) (:content arg Just a thought. I'm sure someone will have a better idea, though. On Apr 21, 1:02 pm, Base wrote: > Hi All - > > I am having a hard time destructuring a nested data structure. > > I am starting out with: > > {:tag :column, > :attrs nil, > :content > [{:tag :name, :attrs nil, :content ["agecat"]} > {:tag :value, :attrs nil, :content ["nil"]} > {:tag :threshold, :attrs nil, :content ["0.05"]}]} > > and am looking to get: > > {:column "agecat", :value "nil", :threshold "0.05"} > > I genearlly 'get' the destructuring and it is very cool, but the > highly nested aspect of this is throwing me off. > > Any thoughts would be most appreciated. > > Thanks > > Bassel > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
One could also do (defn rotate [n s] (let [[front back] (split-at (mod n (count s)) s)] (concat back front))) I was hoping for a moment to avoid calculating (count s) up front, but that definitely does interfere with negative / large shifts, so never mind that. Sincerely, Michał -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Examples of Clojure in production?
On Apr 19, 2010, at 5:55 , Daniel Glauser wrote: > I would like to start a thread about Clojure use in production. Who > is using it? And for what? What kind of load do you have on the > system in terms of approximate transactions per day? Would you mind > if your example was featured in a presentation? Not a big webapp and not many transactions but we use clojure in a final factory test tool I wrote for my team that checks if our installations went well. Works like a charm :). The big + of clojure here is that we don't need to install anything on the machines just copy a jar and run it. Regards, Heinz -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: How do I destructure this?
Damn! This looks pretty good to me. BTW - Love your blog and tutorial videos. they are incredibly helpful and instructive. I have watched many of them more than once. I really appreciate them. Thanks Sean!!! Bassel On Apr 21, 12:07 pm, Sean Devlin wrote: > Hmmm... I'm not sure destructuring is possible here. Would it be > easier to put an extractor fn in place? > > (defn extract > [arg] > (apply hash-map (map (juxt :tag :content) (:content arg > > Just a thought. I'm sure someone will have a better idea, though. > > On Apr 21, 1:02 pm, Base wrote: > > > > > Hi All - > > > I am having a hard time destructuring a nested data structure. > > > I am starting out with: > > > {:tag :column, > > :attrs nil, > > :content > > [{:tag :name, :attrs nil, :content ["agecat"]} > > {:tag :value, :attrs nil, :content ["nil"]} > > {:tag :threshold, :attrs nil, :content ["0.05"]}]} > > > and am looking to get: > > > {:column "agecat", :value "nil", :threshold "0.05"} > > > I genearlly 'get' the destructuring and it is very cool, but the > > highly nested aspect of this is throwing me off. > > > Any thoughts would be most appreciated. > > > Thanks > > > Bassel > > > -- > > You received this message because you are subscribed to the Google > > Groups "Clojure" group. > > To post to this group, send email to clojure@googlegroups.com > > Note that posts from new members are moderated - please be patient with > > your first post. > > To unsubscribe from this group, send email to > > clojure+unsubscr...@googlegroups.com > > For more options, visit this group > > athttp://groups.google.com/group/clojure?hl=en > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
I like that version :) On Apr 21, 1:11 pm, Michał Marczyk wrote: > One could also do > > (defn rotate [n s] > (let [[front back] (split-at (mod n (count s)) s)] > (concat back front))) > > I was hoping for a moment to avoid calculating (count s) up front, but > that definitely does interfere with negative / large shifts, so never > mind that. > > Sincerely, > Michał > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: How do I destructure this?
On 21 April 2010 19:02, Base wrote: > I am having a hard time destructuring a nested data structure. > > I am starting out with: > > {:tag :column, > :attrs nil, > :content > [{:tag :name, :attrs nil, :content ["agecat"]} > {:tag :value, :attrs nil, :content ["nil"]} > {:tag :threshold, :attrs nil, :content ["0.05"]}]} > > and am looking to get: > > {:column "agecat", :value "nil", :threshold "0.05"} If I understand correctly, you want to take the :tag from the top-level map, then reach into the :content vector and extract the maps with either :name or :threshold bound to the :tag key and get something out of their content, right? If so, then you probably don't want to use destructuring, because you don't want to depend on the order in which the submaps occur in the :content of the top-level map. If you can depend on the ordering, then the following would produce your desired result (with your example map previously bound to #'test-map): (let [{tag :tag [{[tag-val] :content} {[value] :content} {t :tag [t-val] :content}] :content} test-map] {tag tag-val :value value t t-val}) This attempts to be somewhat smart in that it figures out that the final key to be put in the result map is :threshold based on the :tag extracted from the last sub-map. So, with consistent structure, that's possible with destructuring -- but it is a bit tedious and fragile. Best to reserve it for the simpler cases, where the exact format of data is likely to remain fixed. (Actually that last part is a must with destructuring.) All in all, I agree with Sean's opinion that an extractor function would be a better fit. Sincerely, Michał -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
On 21 April 2010 19:35, Sean Devlin wrote: > I like that version :) :-) In this case, rotate-while could be rewritten like so: (defn rotate-with [pred s] (let [[front back] (split-with pred s)] (concat back front))) And to round it off with ridiculous overengineering ;-) -- (defn rotate* [n-or-pred s] (let [with? (ifn? n-or-pred) [front back] ((if with? split-with split-at) (if with? n-or-pred (mod n-or-pred (count s))) s)] (concat back front))) Sincerely, Michał -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
wget replacement code review
Hey all, I wrote a clojure version of the simplest functionality of wget. I basically translated the java version into clojure code, but I'm not quite happy with the wget-binary function because I use a loop, and I feel like someone else has a more idiomatic solution to iterating through a java-array. Also, I don't know if my way of handling the no filename case is best. Please tell me how to improve my code, especially in the interop sections. (ns dj (:import [java.io File FileOutputStream BufferedInputStream BufferedReader InputStreamReader]) (:import [java.net URL]) (:require [clojure.contrib [duck-streams :as duck-streams]])) (defn blank? "True if s is nil, empty, or contains only whitespace." [#^String s] (every? (fn [#^Character c] (Character/isWhitespace c)) s)) (defn- extract-url-filename [url] (let [filename (.getFile url)] (if (blank? filename) "index.html" (subs filename 1 (defn- wget-binary [con content-length] (with-open [stream (BufferedInputStream. (.getInputStream con))] (let [data (make-array Byte/TYPE content-length)] (loop [offset 0] (if (< offset content-length) (let [bytesRead (.read stream data offset (- content-length offset))] (if (= bytesRead -1) data (recur (+ offset bytesRead data) (defn- wget-text [url-obj] (with-open [buf (-> url-obj (.openStream) (InputStreamReader.) (BufferedReader.))] (apply str (line-seq buf (defn wget [url-address] (let [url (URL. url-address) filename (extract-url-filename url) con (.openConnection url) content-length (.getContentLength con)] (if (or (= -1 content-length) (.startsWith (.getContentType con) "text/")) (duck-streams/spit filename (wget-text url)) (with-open [out-file (FileOutputStream. filename)] (.write out-file (wget-binary con content-length)) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
If you're gonna over engineer use a protocol :-p On Apr 21, 1:43 pm, Michał Marczyk wrote: > On 21 April 2010 19:35, Sean Devlin wrote: > > > I like that version :) > > :-) > > In this case, rotate-while could be rewritten like so: > > (defn rotate-with [pred s] > (let [[front back] (split-with pred s)] > (concat back front))) > > And to round it off with ridiculous overengineering ;-) -- > > (defn rotate* [n-or-pred s] > (let [with? (ifn? n-or-pred) > [front back] ((if with? > split-with > split-at) > (if with? > n-or-pred > (mod n-or-pred (count s))) > s)] > (concat back front))) > > Sincerely, > Michał > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: wget replacement code review
At first glance, you should be requiring c.c.string, and don't write your own blank? fn. That's the only low hanging fruit I see. On Apr 21, 1:47 pm, Brent Millare wrote: > Hey all, > > I wrote a clojure version of the simplest functionality of wget. I > basically translated the java version into clojure code, but I'm not > quite happy with the wget-binary function because I use a loop, and I > feel like someone else has a more idiomatic solution to iterating > through a java-array. Also, I don't know if my way of handling the no > filename case is best. Please tell me how to improve my code, > especially in the interop sections. > > (ns dj > (:import [java.io File FileOutputStream BufferedInputStream > BufferedReader InputStreamReader]) > (:import [java.net URL]) > (:require [clojure.contrib [duck-streams :as duck-streams]])) > > (defn blank? > "True if s is nil, empty, or contains only whitespace." > [#^String s] > (every? (fn [#^Character c] (Character/isWhitespace c)) s)) > > (defn- extract-url-filename [url] > (let [filename (.getFile url)] > (if (blank? filename) > "index.html" > (subs filename 1 > > (defn- wget-binary [con content-length] > (with-open [stream (BufferedInputStream. (.getInputStream con))] > (let [data (make-array Byte/TYPE content-length)] > (loop [offset 0] > (if (< offset content-length) > (let [bytesRead (.read stream > data > offset > (- content-length > offset))] > (if (= bytesRead -1) > data > (recur (+ offset bytesRead > data) > > (defn- wget-text [url-obj] > (with-open [buf (-> url-obj > (.openStream) > (InputStreamReader.) > (BufferedReader.))] > (apply str (line-seq buf > > (defn wget [url-address] > (let [url (URL. url-address) > filename (extract-url-filename url) > con (.openConnection url) > content-length (.getContentLength con)] > (if (or (= -1 content-length) > (.startsWith (.getContentType con) "text/")) > (duck-streams/spit filename (wget-text url)) > (with-open [out-file (FileOutputStream. filename)] > (.write out-file (wget-binary con content-length)) > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: wget replacement code review
Technically I didn't write my own cause I just copied pasted it ;) For the purposes of this review, just consider that library code or a reference so everyone knows what it does. :) Sean Devlin wrote: > At first glance, you should be requiring c.c.string, and don't write > your own blank? fn. That's the only low hanging fruit I see. > > On Apr 21, 1:47 pm, Brent Millare wrote: > > Hey all, > > > > I wrote a clojure version of the simplest functionality of wget. I > > basically translated the java version into clojure code, but I'm not > > quite happy with the wget-binary function because I use a loop, and I > > feel like someone else has a more idiomatic solution to iterating > > through a java-array. Also, I don't know if my way of handling the no > > filename case is best. Please tell me how to improve my code, > > especially in the interop sections. > > > > (ns dj > > (:import [java.io File FileOutputStream BufferedInputStream > > BufferedReader InputStreamReader]) > > (:import [java.net URL]) > > (:require [clojure.contrib [duck-streams :as duck-streams]])) > > > > (defn blank? > > "True if s is nil, empty, or contains only whitespace." > > [#^String s] > > (every? (fn [#^Character c] (Character/isWhitespace c)) s)) > > > > (defn- extract-url-filename [url] > > (let [filename (.getFile url)] > > (if (blank? filename) > > "index.html" > > (subs filename 1 > > > > (defn- wget-binary [con content-length] > > (with-open [stream (BufferedInputStream. (.getInputStream con))] > > (let [data (make-array Byte/TYPE content-length)] > > (loop [offset 0] > > (if (< offset content-length) > > (let [bytesRead (.read stream > > data > > offset > > (- content-length > > offset))] > > (if (= bytesRead -1) > > data > > (recur (+ offset bytesRead > > data) > > > > (defn- wget-text [url-obj] > > (with-open [buf (-> url-obj > > (.openStream) > > (InputStreamReader.) > > (BufferedReader.))] > > (apply str (line-seq buf > > > > (defn wget [url-address] > > (let [url (URL. url-address) > > filename (extract-url-filename url) > > con (.openConnection url) > > content-length (.getContentLength con)] > > (if (or (= -1 content-length) > > (.startsWith (.getContentType con) "text/")) > > (duck-streams/spit filename (wget-text url)) > > (with-open [out-file (FileOutputStream. filename)] > > (.write out-file (wget-binary con content-length)) > > > > -- > > You received this message because you are subscribed to the Google > > Groups "Clojure" group. > > To post to this group, send email to clojure@googlegroups.com > > Note that posts from new members are moderated - please be patient with > > your first post. > > To unsubscribe from this group, send email to > > clojure+unsubscr...@googlegroups.com > > For more options, visit this group > > athttp://groups.google.com/group/clojure?hl=en > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
In some languages, split-at is more performant than doing take and drop separately. But in Clojure, split-at is simply defined as: (defn split-at "Returns a vector of [(take n coll) (drop n coll)]" [n coll] [(take n coll) (drop n coll)]) So by using split-at, you gain nothing other than the additional overhead of constructing a vector and then turning around and destructuring it. On Wed, Apr 21, 2010 at 10:11 AM, Michał Marczyk wrote: > One could also do > > (defn rotate [n s] > (let [[front back] (split-at (mod n (count s)) s)] > (concat back front))) > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Coordinated, asynchronous modification of state?
What you are talking about is commonly referred to as a "barrier" in parallel processing. All processes coordinated on a given barrier must each reach the barrier before any one may cross it. Simply putting a barrier check into the message queue of an Clojure agent would not be sufficient as I understand the agents to be free to re-order message processing. You could build an ordered message queue with one of the other types like ref, and have threads for processing each queue, that will appropriately block on barriers. That seems straightforward (it's possible there is some other feature in clojure I'm unaware of that will give you this) Kevin On Apr 21, 9:56 am, Garth Sheldon-Coulson wrote: > Hi All, > > The moment one sends a post one starts thinking about it from a critical > perspective. > > I think I may have grown so used to the idea that nothing in Clojure can > deadlock that I completely overlooked the possibility of deadlock in the > idea I proposed. If two serfs are the targets of two different transactions, > and those transactions happen to enter the serfs' queues in different > orders, the serfs will wait forever for each other to become free. Classic > deadlock. > > So, this stands as a challenge: Is there any way to get coordinated, > asynchronous, guaranteed-in-order modification of state? Or is it a pick-two > situation? > > Thanks, > Garth > > On Wed, Apr 21, 2010 at 11:29 AM, Garth Sheldon-Coulson wrote: > > > > > Hi All, > > > This e-mail is the product of some musing about refs, agents, and atoms. I > > would like to offer some thoughts on a possible fourth reference type that > > allows coordinated, asynchronous modification of state. > > > I would greatly appreciate comments from the community. Maybe some of these > > ideas have already been discussed on the list or incorporated into > > development, in which case I'm sorry for repeating what is already > > known---and please point me in the right direction so I can read more. I > > hope the ideas are not too far off base, but please let me know if you think > > they are. > > > Let me start at the beginning. In Clojure, we have standard reference types > > for: > > > * uncoordinated, synchronous state change, > > * coordinated, synchronous state change, > > * uncoordinated, asynchronous state change. > > > Most Clojure users are familiar with the following diagram expressing the > > reference type taxonomy. (The ASCII diagrams in this e-mail are best viewed > > in a fixed-width font.) > > > | Synchronous | Asynchronous > > --+--+- > > Uncoordinated | Atoms | Agents > > Coordinated | Refs | > > > It occurred to me recently that there is no built-in reference type for the > > final quadrant: coordinated, asynchronous change. There is no reference > > type, in other words, allowing one to write a "doasync" block similar to a > > dosync block: > > > (doasync ;short for do asynchronously > > (send a inc) > > (send b inc)) > > > causing a and b to change together atomically in the background. I thought > > to myself that it would be nice to have this ability in some applications, > > especially simulation, artificial life, and agent-based modeling. It allows > > one thread to effect coordinated change in other threads while getting on > > with its own work. > > > I pondered more and realized that, although there is no built-in reference > > type for this purpose, one can make a first stab at the same effect using a > > combination of futures and refs: > > > (future > > (dosync > > (alter a inc) > > (alter b inc))) > > > The future wraps the atomic transaction and causes it to take place in a > > background thread. > > > This solution satisfied me for a day or two. Upon some more thought, > > however, I realized that combining refs with futures is a recipe for > > livelock disaster. Here is why. In a massively concurrent program with heavy > > asynchronous state change, it is unlikely that any one ref will stay the > > same for very long. The kind of coordinated change offered by a ref > > transaction is unlikely to be successful in this kind of constantly-changing > > environment, because the values of the refs are constantly being changed out > > from under the transaction attempts. Consider the following illustration, in > > which I try to modify a ref at the same time that it is being changed > > continually from another thread: > > > begin example > > (def a (ref 1)) > > > ; the code for start-frequent-changes is at > > ;http://gist.github.com/373143 > > (start-frequent-changes a) > > > ; this code will never print its message > > (let [done? (agent nil)] > > (future > > (dosync > > (alter a (fn negate [val] (Thread/sleep 300) (- val))) > > ; negate is a long-running function of its argument > > (send done? (fn [_] (println "Done!")) > > end example > > > The
Re: How do I destructure this?
Thanks Michal - I have done a little digging into juxt (reading the great write up that Sean previously posted here - great post by the way) and it is a very slick way to deal with this issue. I am always amazed at the createive and concise solutions that Clojure enables. Thanks much for all of your help guys. On Apr 21, 12:36 pm, Michał Marczyk wrote: > On 21 April 2010 19:02, Base wrote: > > > I am having a hard time destructuring a nested data structure. > > > I am starting out with: > > > {:tag :column, > > :attrs nil, > > :content > > [{:tag :name, :attrs nil, :content ["agecat"]} > > {:tag :value, :attrs nil, :content ["nil"]} > > {:tag :threshold, :attrs nil, :content ["0.05"]}]} > > > and am looking to get: > > > {:column "agecat", :value "nil", :threshold "0.05"} > > If I understand correctly, you want to take the :tag from the > top-level map, then reach into the :content vector and extract the > maps with either :name or :threshold bound to the :tag key and get > something out of their content, right? > > If so, then you probably don't want to use destructuring, because you > don't want to depend on the order in which the submaps occur in the > :content of the top-level map. > > If you can depend on the ordering, then the following would produce > your desired result (with your example map previously bound to > #'test-map): > > (let [{tag :tag > [{[tag-val] :content} > {[value] :content} > {t :tag [t-val] :content}] > :content} > test-map] > {tag tag-val :value value t t-val}) > > This attempts to be somewhat smart in that it figures out that the > final key to be put in the result map is :threshold based on the :tag > extracted from the last sub-map. So, with consistent structure, that's > possible with destructuring -- but it is a bit tedious and fragile. > Best to reserve it for the simpler cases, where the exact format of > data is likely to remain fixed. (Actually that last part is a must > with destructuring.) > > All in all, I agree with Sean's opinion that an extractor function > would be a better fit. > > Sincerely, > Michał > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
Hmmm... we could talk about what's faster or measure it. Time to eat my own damn dog food, I guess :) Traveling now, I'll run the experiments in a few days when I get back to my normal setup. Sean On Apr 21, 2:09 pm, Mark Engelberg wrote: > In some languages, split-at is more performant than doing take and > drop separately. But in Clojure, split-at is simply defined as: > (defn split-at > "Returns a vector of [(take n coll) (drop n coll)]" > [n coll] > [(take n coll) (drop n coll)]) > > So by using split-at, you gain nothing other than the additional > overhead of constructing a vector and then turning around and > destructuring it. > > On Wed, Apr 21, 2010 at 10:11 AM, Michał Marczyk > > wrote: > > One could also do > > > (defn rotate [n s] > > (let [[front back] (split-at (mod n (count s)) s)] > > (concat back front))) > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
On 21 April 2010 19:57, Sean Devlin wrote: > If you're gonna over engineer use a protocol :-p You're absolutely right, of course; I stand corrected! Here's my new attempt at overengineering then: (defprotocol Rotator (rotate [self s])) (extend-protocol Rotator Number (rotate [self s] (let [[front back] (split-at (mod self (count s)) s)] (concat back front))) clojure.lang.IFn (rotate [self s] (let [[front back] (split-with self s)] (concat back front Funnily enough, I actually find this vaguely reasonable. :-) Sincerely, Michał -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Arguments for < and > et al
== < <= > >= are all numeric equality/comparison functions. = and 'compare are object equality/comparison functions. On Apr 20, 6:47 pm, Bill Allen wrote: > I've been writing a program that requires the use of java.util.Calendar and > its descendent java.util.GregorianCalendar. One thing I'd hoped to do was > compare two Calendar objects with <, but the compiler complained that the > arguments to < didn't inherit from Number which was a surprise to me because > Calendar does inherit from java.lang.Comparable which in java land would be > sufficient to enable it to be compared with other members of its class using > the built in java comparison operators. Since I know that clojure has other > operations that deal with comparable, I assume this is a conscious decision, > but I question why it should be so. > > Regards, > Bill > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
On 21 April 2010 20:09, Mark Engelberg wrote: > In some languages, split-at is more performant than doing take and > drop separately. But in Clojure, split-at is simply defined as: > (defn split-at > "Returns a vector of [(take n coll) (drop n coll)]" > [n coll] > [(take n coll) (drop n coll)]) > > So by using split-at, you gain nothing other than the additional > overhead of constructing a vector and then turning around and > destructuring it. I realise that, however I find that there is also a slight gain in readability / aesthetic appeal of the code; buying that at the minute cost incurred due to creating and destructuring a vector seems acceptable to me. As an aside, it might actually be possible to write a more efficient split-at -- perhaps exploiting the nature of the sequence being split (e.g. you could use (seq (subvec ...)) with vectors) -- should the need arise, so maybe it will become beneficial from the performance POV at some point... Sincerely, Michał -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: request for comments/code-review - clojure implementation of unifier
Thank you for taking the time to provide feedback. > I can't think of a direct equivalent now, but it's straightforward > enough to supply your own equivalent, like my compound? function > (basically #(and (seq? %) (seq %))). This won't work on arrays and > other things which seq can operate upon, but which respond with a > false to seq?, though. If that could be a problem, you can just use > seq and for non-seqables catch the exception and return false. intentionally driving into an exception seems like a very bad idea. but yes I can define my own equivalent of consp I was just hoping there was something I was over looking. > You could perform a CPS transform by hand (which I haven't (yet) done > with the code in the Gist). For occurs-check this would mean having an > extra to-do argument (or maybe just [... & to-do]); whenever false > would normally be returned, you'd first check if to-do is empty, > returning false if so and doing (recur > (rest to-do)) otherwise. true should short-circuit and disregard > to-do, of course. Finally, whenever occurs-check would normally branch > on first / rest, it would recur with first *and* an extended to-do > including rest. That'll trade some heap for stack space, presumably worthwhile. I haven't had to do much hand optimization of recursion so I'm a little rusty (the Franz Allegro compiler was fairly amazing in that regard)... I was hoping there was some even better trick (like the trampoline) to save me even more. That's a good idea though, I'll just to estimate how close I'm getting to blowing the stack, and the overhead of tracking to-do. > Not at all. next is basically #(seq (rest %)); you might want to use > it when the extra bit of strictness is beneficial to your code and you > shouldn't use it when it isn't. oh, ok. I saw some posts on using the new super-lazy lists / code and it implied that next was necessary over rest, but I didn't quite read it in excruciating detail. > Good question. I really prefer the fully parenthesised cond clauses > from Scheme / CL / elisp, in good part because of the nicer > indentation without particularly elaborate rules... :-( that "extra" paren is there too because the body of the clause is an implicit progn in common lisp. > I think that your code would benefit from direct use of Clojure data > structure literals and such facilities as the IFn implementation > available on maps; see my gist for examples of what I have in mind. on some issues I agree others I disagree, regarding your code: regarding removing the helper functions, that's not necessarily ideal, while bindings may always be a map putting in literals like {} or nil instead of fail or no-bindings actually obfuscates the code, and makes it harder to change later if what bindings is needs to fundamentally change. similarly with truncating variable names, it detracts from readability - although with one interesting caveat -- "var" is a particularly unique as it is now a language keyword in clojure. in general it's bad style to wrap a cond with another test if trivially avoidable (at least this is coming from best practice common lisp style) so for example, in your code line 24, there's no reason to pull that out of the cond, especially since you are also using the return value of the when, it's better to be explicit about the test and what it's resulting return value is -- in this case that the unification fails. the if-let's are a little more interesting as it potentially saves one lookup, but it seems to make the code far more "disjoint" or at least increase the number of paths. the changing of a cond to a some with the identity function on line 48 seems like a very odd choice to me. while still correct code I see no reason why this would be preferred to a cond. thanks for the subst code. I'm torn about the simplify-bindings -- I think it's a cool function to have, because if what you are subbing into is large compared to bindings, this is probably a win, but if you have a lot of bindings and are only using some, you could spend a lot of time to pack them down. it'd probably be good to have around if someone knew where they were in the trade-off. I left out Norvig's code, I have a need for binding/substituting with multiple binding lists so I ended up with this (which requires clojure.walk) (defn recursive-replace ([expr l-bindings] (recursive-replace expr l-bindings #{expr})) ([expr l-bindings past-vals] (let [applicable-bindings (some (fn [b] (if (contains? b expr) b nil)) l-bindings) bind-val (get applicable-bindings expr)] (if (or (not applicable-bindings) (contains? past-vals bind-val)) ;don't enter replace loop expr (recur bind-val l-bindings (conj past-vals bind-val)) (defn subst-bindings-int [x l-bindings] (prewalk (fn [expr] (recursive-replace expr l-bindings)) x)) (defn subst-bindings-list [x list-of-bindings] (cond (some (partial = fail) list-of
Re: Documentation (was: Re: duck-streams missing from clojure-contrib.jar file)
Hi all, (For those who don't know, I'm the one who maintains the autodoc API documentation.) There are some great suggestions here and I'll try to pick up as many as I can. More useful branch names and having the branch in the title are no brainers and I'll try to get them in soon. One resource to use is the index included with each API. (See the index link in the left sidebar.) This has every function, macro and var in the whole library with a snippet of their doc. I find this to be pretty useful sometimes, especially when I don't remember which namespace something's in. I've always wished the Python doc had this feature! A couple things I've also been thinking about are building in a search capability and building a "super-index" of not only core and contrib but various other external libraries that would link back to their doc. Please also understand that Clojure is a young language and things are still very much under development. We're still understanding what our "best practice" is and how to approach it. As you point out, clojure.contrib.io is an example where we're not there yet, but it is happening. clojure.contrib.io is a precursor for a clojure.io namespace that will unify these things. Thanks for the ideas! Keep 'em coming. Tom On Apr 21, 8:39 am, Douglas Philips wrote: > On 2010 Apr 21, at 9:31 AM, Stuart Halloway wrote: > > > The second level header tells you the branch (e.g. master). On the > > left hand side is a list of branches (so you can click on e.g. 1.1.x). > > Wow, that is quite subtle. As you click into contrib from clojure.org > it isn't very noticeable. > It also isn't something you notice if you are, for example, clicking > through from the unversioned clojure.org pages. > An example at random: > Start at:http://clojure.org/macros > then click on the lazy-cat link, which takes you > to:http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/ > lazy-cat > and start browsing. > > With your focus down 'into' that page you have no idea that you've > jumped into versioned information. > > If you start as a beginner, as I did, the stuff on clojure.org is not > versioned (there is no master/1.1.x link in the side bar) and so > having version info appear only in contrib pages is not easy to > notice, particularly if you get there via links from the main page. > > > Some ways I see this might be better: > > > (1) make clear what master currently equals (right now it is 1.2 > > alpha) > > That would help. Master is pretty generic. > > > (2) highlight the branch info more with css > > Couldn't hurt, but it it'd be nice if showed in the page title too, > the sidebars are lost when scrolling down into the various pages. > > > (3) push the branch info into the top-level header (and page title) > > Yup. > > > (4) The overview section for c.c.io could tell about the lineage > > back to 1.1. > > Not having been along for the ride since (nearly) the beginning, > having those breadcrumbs would be helpful to me. > > > Which of these (or what else?) would have helped you the most? > > I think having the default, as Alex Osburne suggested, be the stable > release would have made my exploration of 1.1 a lot less painful. > > And along those lines, distinguishing between core and contrib is > something that might be important to the maintainers, but not so much > to the users. And, very less useful to newbies trying to get something > useful done. > > Trying to figure out that spit is in a contrib library and slurp > isn't? C'mon. I finally broke down and used google, and then when I > saw a thread back in '08 about that, and it still isn't addressed? > Really, easy file I/O is that unimportant to most clojure users? > > Having a unified and comprehensive index of functions/macros > (annotated with core/contrib) would also go a long way to making the > clojure documentation environment a lot more useful. Oh, and then > there is the distinction betweenhttp://clojure.org/librariesand the > contrib libraries. Yet another place to look? Great, I really don't > have anything better to do than internalize these distinctions? (In > case you can't tell, having burned -hours- of spare time trying to > find my way around docs has been exceptionally frustrating.) > > At least for someone like me who is exploring on their own and isn't > getting paid to make this work, having to lose my train of thought for > 5-10 minutes while trying to figure out if something is core or > contrib is hugely frustrating and demotivating. Then throw in a "wtf? > why isn't this working in the stable release" only makes it more so > when I'm looking at the wrong docs and didn't even know that there > were versioned docs. > > If you want an example of the kind of structure that I do find > helpful, look at docs.python.org. How many times on that page do you > see that you're lookin at the 2.6 docs and that there are links to > o
Re: request for comments/code-review - clojure implementation of unifier
Kevin Livingston writes: >> Not at all. next is basically #(seq (rest %)); you might want to use >> it when the extra bit of strictness is beneficial to your code and you >> shouldn't use it when it isn't. > > oh, ok. I saw some posts on using the new super-lazy lists / code and > it implied that next was necessary over rest, but I didn't quite read > it in excruciating detail. Likely what you were reading was referring to nil-punning. In very early versions of Clojure, empty seqs were nil, so you could do: (when some-seq ...) Of course this has the problem that you can't have a completely lazy seq, the first element is always evaluated (to see whether the seq is empty or not in order to return nil). They were made fully lazy by introducing empty seqs, thus you now need to explicitly check with one is empty use 'seq. So next is a shorthand for doing this on rest and replacing instances of rest with next in old code that relied on nil-punning was a simple way to upgrade. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: getting compiler-like meta data from read
Thank you the LineNumberingPushbackReader is exactly what is needed. The other metadata I can add fairly straightforwardly so good, this is *far* more sane than that monstrosity I conjured up. Kevin On Apr 20, 3:15 am, Ilia Ablamonov wrote: > I've encountered the same problem (as far as I understood) in Fleet. > > My solution > ishttp://github.com/Flamefork/fleet/blob/master/src/fleet/loader.clj#L55 > > There code comes from String, but you can use FileReader instead of > StringReader. > File path must be specified additionally, but this should be obvious. > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Documentation (was: Re: duck-streams missing from clojure-contrib.jar file)
On Thursday, April 22, 2010, Tom Faulhaber wrote: > > A couple things I've also been thinking about are building in a search > capability and building a "super-index" of not only core and contrib > but various other external libraries that would link back to their > doc. I think building a super index is a great idea and would be very useful. The current indexes are great because you can easily search for a function on one page. Anything that reduces the number of pages you need to visit to find stuff is useful in my opinion. The ultimate would be something that let's users contribute their own comments but that may be going beyond the scope of what you want autodoc to be. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Which version of Netbeans to use Compojure on OSX?
I see downloads named - Java SE (45MB) - Java FX (76MB) - Java (146MB) - apparently includes Sun Glassfish Server & what-not I'm using OSX 10.5.8, and just want to install the easiest Netbeans (with Enclojure) to for development with Compojure. Would I use Compojure with Jetty? Apache (built into OSX)? Thanks! -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Which version of Netbeans to use Compojure on OSX?
If you've got the HD space, grab the most inclusive options. I *think* the SE one will work, but I haven't tested it. Space is cheap and all that. On Apr 21, 7:55 pm, Sophie wrote: > I see downloads named > - Java SE (45MB) > - Java FX (76MB) > - Java (146MB) - apparently includes Sun Glassfish Server & what-not > > I'm using OSX 10.5.8, and just want to install the easiest Netbeans > (with Enclojure) to for development with Compojure. > > Would I use Compojure with Jetty? Apache (built into OSX)? > > Thanks! > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group > athttp://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Which version of Netbeans to use Compojure on OSX?
On 22/04/2010, at 10:48 AM, Sean Devlin wrote: > I think* the SE one will work, but I haven't tested it. Yes it does. Antony Blakey -- CTO, Linkuistics Pty Ltd Ph: 0438 840 787 If at first you don’t succeed, try, try again. Then quit. No use being a damn fool about it -- W.C. Fields -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
Yet another variation: (defn conjugate [f g & [g-inv]] (comp (or g-inv g) f g)) (defn composite [f f-inv n x] (nth (iterate (if (pos? n) f f-inv) x) (abs n))) (defn rotate-left [xs] (when (seq xs) (concat (rest xs) [(first xs)]))) (def rotate-right (conjugate rotate-left reverse)) (defn rotate [n xs] (composite rotate-left rotate-right n xs)) This is intended to expose certain symmetries. One of the basic ideas in mathematics is that an invertible transformation T acts on elements by application, so that x becomes T(x), and on functions by conjugation, so that f becomes T^(-1) . f . T. Another basic idea is that iterated compositions are like powers: f^n is the n-fold composition of f. This is what iterate tries to capture. This is meaningful for negative values of n when f is invertible. This is what composite tries to capture. If there were more direct support for doubly-infinite sequences (a fun little programming exercise) then composite could return a doubly-infinite sequence (much like iterate returns a singly-infinite sequence), take would work with negative arguments, next would have a counterpart prev, etc. Another fun exercise is to provide more direct support for invertible functions. An invertible function can be represented by a pair of functions. It implements IFn by applying the first element of the pair. Inverting is just a matter of swapping the elements. Food for thought. :) -Per On Wed, Apr 21, 2010 at 10:23 PM, Sean Devlin wrote: > Hey everyone, > > I've had to code these guys up a few times: > > (defn rotate > "Take a collection and left rotates it n steps. If n is negative, > the > collection is rotated right. Executes in O(n) time." > [n coll] > (let [c (count coll)] > (take c (drop (mod n c) (cycle coll) > > (defn rotate-while > "Rotates a collection left while (pred item) is true. Will return a > unrotated > sequence if (pred item) is never true. Executes in O(n) time." > [pred coll] > (let [head (drop-while pred coll)] > (take (count coll) (concat head coll > > Have other people had this problem? > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: request for comments/code-review - clojure implementation of unifier
On 21 April 2010 22:58, Kevin Livingston wrote: > Thank you for taking the time to provide feedback. Thank you for the insightful response! I've posted the current state of my code -- which uses clojure.zip and clojure.walk, among other things -- here: http://gist.github.com/374764 > intentionally driving into an exception seems like a very bad idea. > but yes I can define my own equivalent of consp I was just hoping > there was something I was over looking. Right. I've aliased clojure.contrib.core/seqable? to compound? for now... which I hadn't known about earlier. I guess this was bound to be a solved problem. Agreed on the use of exceptions. > That'll trade some heap for stack space, presumably worthwhile. I > haven't had to do much hand optimization of recursion so I'm a little > rusty (the Franz Allegro compiler was fairly amazing in that > regard)... I was hoping there was some even better trick (like the > trampoline) to save me even more. I did write a version of occurs-check -- which I seem to have renamed to occurs? at some point -- which uses the CPS approach (it's included in the Gist, commented out); then I realised that its a natural use case for clojure.zip (the same basic idea, but with a different packaging). See if you like the current version. > that "extra" paren is there too because the body of the clause is an > implicit progn in common lisp. And an implicit begin in Scheme, I know... Plus the Scheme version handles unary clauses and a special kind of ternary clauses (with '=> in the middle) in special ways, which is useful at times. However, the reason I personally prefer to have those extra parens in cond has much more to do with the shape of the code than those other things. :-) > on some issues I agree others I disagree, regarding your code: Thanks again for your remarks. A few points that came to my mind: > regarding removing the helper functions, that's not necessarily ideal, > while bindings may always be a map putting in literals like {} or nil > instead of fail or no-bindings actually obfuscates the code, and makes > it harder to change later if what bindings is needs to fundamentally > change. I'm in two minds w.r.t. the second point above. On the one hand, I'm loathe to pass on using such facilities as the IFn implementation on maps, sets and vectors in an attempt to make easier some fundamental change which might possibly happen in the future (and who knows what else it might involve besides what I might think of now). On the other, I can already see a different data structure being useful for representing bindings (more on that further down), so I'm also disinclined to hand-wave your argument away. However, I do believe that said different data structure could be made to act like a map fairly transparently (hopefully through the protocol facility; or, if some functionality's missing as of yet, reify), so I'd still prefer to use the map-specific niceties and refactor to remove them only when the need actual comes (and it becomes clear what sort of changes are really needed). > in general it's bad style to wrap a cond with another test if > trivially avoidable (at least this is coming from best practice common > lisp style) so for example, in your code line 24, there's no reason to > pull that out of the cond, especially since you are also using the > return value of the when, it's better to be explicit about the test > and what it's resulting return value is -- in this case that the > unification fails. Well, I was trying to treat failure specially, as it were, but I take your point. Changed now. > the if-let's are a little more interesting as it > potentially saves one lookup, but it seems to make the code far more > "disjoint" or at least increase the number of paths. I've included my cond-let macro in the Gist now (and refactored unify-variable to take advantage of it); do you think it's acceptable? > the changing of a cond to a some with the identity function on line 48 > seems like a very odd choice to me. while still correct code I see no > reason why this would be preferred to a cond. Ouch, I don't know what I was thinking. Changed now. > I'm torn about the simplify-bindings -- I think it's a cool function > to have, because if what you are subbing into is large compared to > bindings, this is probably a win, but if you have a lot of bindings > and are only using some, you could spend a lot of time to pack them > down. it'd probably be good to have around if someone knew where they > were in the trade-off. Perhaps using some kind of local memoization would be a good compromise? There was a cool thread on memoization here a short while ago; see Meikel Brandmeyer's summary here: http://kotka.de/blog/2010/03/memoize_done_right.html I took a shot at that with subst-memo. Additionally, this function leaves unbound variables intact, while the other versions use nil instead. There are two other (simpler) versions of subst included in the curren
Re: Missing fns: rotate & rotate-while
On 22 April 2010 03:51, Per Vognsen wrote: > Yet another variation: > > [...] > > Food for thought. :) This is absolutely beautiful. I feel a tremendous joy now. :-) Sincerely, Michał -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Which version of Netbeans to use Compojure on OSX?
Get the SE version. You can add other parts that are included in the other versions (JavaFX, JEE, etc) using the NetBean's plugin mechanism if you find that you need them. (In the menu bar select Tools -> Plugins) On Wed, Apr 21, 2010 at 18:18, Sean Devlin wrote: > If you've got the HD space, grab the most inclusive options. I > *think* the SE one will work, but I haven't tested it. Space is cheap > and all that. > > On Apr 21, 7:55 pm, Sophie wrote: > > I see downloads named > > - Java SE (45MB) > > - Java FX (76MB) > > - Java (146MB) - apparently includes Sun Glassfish Server & what-not > > > > I'm using OSX 10.5.8, and just want to install the easiest Netbeans > > (with Enclojure) to for development with Compojure. > > > > Would I use Compojure with Jetty? Apache (built into OSX)? > > > > Thanks! > > > > -- > > You received this message because you are subscribed to the Google > > Groups "Clojure" group. > > To post to this group, send email to clojure@googlegroups.com > > Note that posts from new members are moderated - please be patient with > your first post. > > To unsubscribe from this group, send email to > > clojure+unsubscr...@googlegroups.com > > For more options, visit this group athttp:// > groups.google.com/group/clojure?hl=en > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > -- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Brian Schlining bschlin...@gmail.com -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Documentation (was: Re: duck-streams missing from clojure-contrib.jar file)
On 2010 Apr 21, at 5:04 PM, Tom Faulhaber wrote: (For those who don't know, I'm the one who maintains the autodoc API documentation.) Cool, thank you! One resource to use is the index included with each API. (See the index link in the left sidebar.) I saw that, but you know, after finding out that "Branches" and "Overview" and "Namespaces" don't do anything, I had just assumed that "API Index" didn't do anything either; based on clicking those headers when first landing on the contrib page. Sigh. This has every function, macro and var in the whole library with a snippet of their doc. I find this to be pretty useful sometimes, especially when I don't remember which namespace something's in. I've always wished the Python doc had this feature! Python does come close: http://docs.python.org/genindex-all.html (It takes a few clicks from the main docs page: library -> index -> full-index-on-one-page. It does show you the library location, but not any part of the individual documentation.) (I'm used to using the Python 2.4 docs since my day job situation uses that older version: http://docs.python.org/release/2.4.4/lib/genindex.html) A couple things I've also been thinking about are building in a search capability and building a "super-index" of not only core and contrib but various other external libraries that would link back to their doc. Having one index that spans the core and the contrib library would be a huge step forward. Adding in other stuff would be cool, but I would hope that would not delay work unifying core/contrib. Please also understand that Clojure is a young language and things are still very much under development. Yup. We're still understanding what our "best practice" is and how to approach it. As you point out, clojure.contrib.io is an example where we're not there yet, but it is happening. clojure.contrib.io is a precursor for a clojure.io namespace that will unify these things. Looking at the clojure.org front page, there is no "roadmap" link, or anything that seems to be like that, to know what is on the radar, etc. The "news" link points to: http://clojure.blogspot.com/ but that seems to be a few months old. Clicking through the 'dev' link and bouncing around, I eventually found: http://www.assembla.com/spaces/clojure/milestones/149827-release-1-2 and it seems that there are only a handful of issues to be resolved before 1.2 is cut? Poking around a bit more, I found bug 282 having to do with fixing the already changed duck-streams to io in test comments. Maybe I missed some other link(s) that would show a higher level view of what is planned? Thanks for the ideas! Keep 'em coming. Thank you for listening. -Doug -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Missing fns: rotate & rotate-while
By the way, once you start looking for conjugation in common code patterns, you see it everywhere. A less trivial example is the Schwartzian transform for caching sorting keys: (defn schwartz [key-fn] #(map (fn [x] [(key-fn x) x]) %)) (def unschwartz #(map second %)) (defn schwartz-sort [key-fn] (conjugate sort (schwartz key-fn) unschwartz)) If you implement first-class support for invertible functions (surprisingly easy), you can capture important properties such as: - composing invertible functions gives an invertible function. - the inverse of an invertible function is an invertible function. >From this, it follows (with no extra work) that the conjugate transformation of an invertible function is an invertible function. -Per On Thu, Apr 22, 2010 at 10:38 AM, Michał Marczyk wrote: > On 22 April 2010 03:51, Per Vognsen wrote: >> Yet another variation: >> >> [...] >> >> Food for thought. :) > > This is absolutely beautiful. I feel a tremendous joy now. :-) > > Sincerely, > Michał > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en