Re: Critiques of "my-flatten" which uses CPS

2014-07-17 Thread Mark P
One other question occurs to me re your comment...

It's worth understanding how to go back and forth between accumulator-style 
> and a lazy construction.  You can convert the above non-lazy accumulator 
> version into a similar version that is lazy but has no risk of stack 
> overflow in the realization of that lazy flattened list:
>

Why does going lazy avoid a stack overflow risk?

Again, to answer my own question :-) ...  The resultant flat list from 
my-flatten will be realized one element at a time.  The call stack will be 
used during this process, but lazy-seq prevents it getting very deep.  I 
think lazy-seq is a bit like a thunk (invoked via the seq call), except 
that it also caches the result.  So its like the thunks in our 
trampolining, except that the "bouncing" doesn't occur eagerly as with 
trampolining, but only on-demand as a consumer traverses the flat list.

Is this a good way of thinking about it?
 

>
> (defn my-flatten
>   [xs]
>   (if (empty? xs) ()
> (let [x (first xs), ys (rest xs)]
>   (if (sequential? x)
> (if (seq x)
>   (recur (cons (first x) (cons (rest x) ys)))
>   (recur ys))
> (lazy-seq (cons x (my-flatten ys)))
>
> Basically, you just get rid of the accumulator, and in the place where you 
> would have conj'd in the next atomic element, you just build the lazy 
> sequence.
>
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of "my-flatten" which uses CPS

2014-07-17 Thread Mark P
Woopse, typo towards the end of my last post...

Maybe the thing to do would be to use (next x) here for this 
> implementation, which is angling to be lazy...  But in your earlier 
> acc-based my-flatten, to use (next x) instead
>

Should be...  Maybe the thing to do would be to use (rest 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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of "my-flatten" which uses CPS

2014-07-17 Thread Mark P
Coming back to your helpful comments about relationship between acc-style 
and lazy...

It's worth understanding how to go back and forth between accumulator-style 
> and a lazy construction.  You can convert the above non-lazy accumulator 
> version into a similar version that is lazy but has no risk of stack 
> overflow in the realization of that lazy flattened list:
>

I notice in your lazy version (below), you preface the last cons with a 
lazy-seq call, but do not do the same with the other cons calls (within the 
first recur form).  I know it was only the last line that previously had a 
conj call and so participated in this transformation... but I'm wondering 
why you wouldn't also use lazy-seq with the other cons-involving line?

To answer my own wondering, I am thinking it is for two reasons:

   1. The main reason for using lazy-seq in the last line is to defer the 
   recursive call to my-flatten until something wants to use it.  In contrast, 
   the other cons-involving line only conses up things which are relatively 
   harmless to evaluate.
   2. The "cons (first x) ..." will be "undone" almost immediately after 
   the recur is executed, via the "(first xs)".  So inserting laziness here is 
   counter productive.

Another question...

I notice that you bound ys to (rest xs), in contrast to my choice of (next 
xs) in some of my implementations.  I realize this is probably a minor 
point, but just wondering whether (rest xs) was a deliberate choice of 
yours, or just habit.  I realize that rest maximizes laziness in contrast 
to next, but do we want maximum laziness here?

To again attempt to answer my own question...  It probably depends on what 
xs is being passed into my-flatten.  It xs is a fully realized sequence, 
then (next x) would probably do.  But if xs is itself lazy (and possibly 
expensive to compute), then using (rest x) maximizes our laziness 
opportunity.

Maybe the thing to do would be to use (next x) here for this 
implementation, which is angling to be lazy...  But in your earlier 
acc-based my-flatten, to use (next x) instead, because this implementation 
is eager and we know we're going to realize all of xs at some point anyway. 
 It this logic sound?  (I realize I am being pedantic, but I'm trying to 
understand the principles involved.)

Thanks again for showing me the relationship between acc-based and lazy - 
helpful!


> (defn my-flatten
>   [xs]
>   (if (empty? xs) ()
> (let [x (first xs), ys (rest xs)]
>   (if (sequential? x)
> (if (seq x)
>   (recur (cons (first x) (cons (rest x) ys)))
>   (recur ys))
> (lazy-seq (cons x (my-flatten ys)))
>
> Basically, you just get rid of the accumulator, and in the place where you 
> would have conj'd in the next atomic element, you just build the lazy 
> sequence.
>
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of "my-flatten" which uses CPS

2014-07-16 Thread Mark P
Interesting - thank you!

Good to know about "into" as a way to achieve a non-lazy concat - in 
conjunction with a vector.

I like your accumulator version - morphing the structure of the input as 
you go to achieve the desired result.

I've come up with another version, that passes through both a "result so 
far" accumulator and a "still to be computed" stack.  It is very much 
non-lazy, but that's okay in some applications (a performance feature 
even!).  Here it is...

(defn my-accandstackbased-flatten
  [xs]
  (letfn [(flatten-accandstack [xs accvec stackvec]
(if (empty? xs)
  (if (empty? stackvec)
accvec
(recur (peek stackvec) accvec (pop stackvec)))
  (let [x (first xs), ys (next xs)]
(if (sequential? x)
  (recur x accvec (conj stackvec ys))
  (recur ys (conj accvec x) stackvec)]
(seq (flatten-accandstack xs [] []

This has nice recur behaviour and doesn't mess too much with the structure 
of the input nested lists.  In the case of flatten, retaining structure is 
not important (as you nicely illustrated), but there are generalizations of 
this kind of function where retaining structure becomes more important.

Now here's the thing...  In the above, my stackvec is sort of like a 
continuation.  It contains a stack of computation to be performed later on. 
 That sounds very much like a continuation to me (though I am still in the 
process of getting my head around this stuff).  So I've thought, surely I 
could write an "acc and cps" version of my-flatten?  Here is what I came up 
with...

(defn my-accandcpsbased-flatten
  [xs]
  (letfn [(flatten-accandcps [xs accvec k]
(if (empty? xs)
  (k accvec)
  (let [x (first xs), ys (next xs)]
(if (sequential? x)
  (recur x accvec (fn [v] (flatten-accandcps ys [] (fn [w] 
(k (into v w))
  (recur ys (conj accvec x) k)]
(seq (flatten-accandcps xs [] identity
 
And I could do the trick you showed me with thunks and a trampoline, if I 
wanted to make it completely stack-avoiding.

What does this show?  I'm not sure.

Presumably the acc and stack version is the most efficient as it uses recur 
everywhere?

The structure of the continuation I pass in with the "acc and cps" version 
is very similar in complexity to the continuation I passed as part of my 
original cps implementation.  So where's the gain?  I guess the inclusion 
of an accvec means that continuations are generated less frequently so that 
the overall size and execution time of continuations is smaller?  And it is 
an improvement over my earlier aps version that used only an acc vector - 
because this version has everything in tail-call position and is amenable 
to trampolining.

Is this attempt at analysis reasonable?  Is there anything else worth 
observing etc?

Presumably I could make the "acc and cps" above more lazy using concat, 
cons and lazy-seq.  I'd need to think about how easy/hard it would be to 
make my "acc and stack" version as lazy.

Thanks again for your helpful comments and examples.

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Critiques of "my-flatten" which uses CPS

2014-07-15 Thread Mark P
Thanks for explaining how one creates a trampolined version from the cps 
version!  This makes sense.

Thanks also for alerting me to potential issues with the concat laziness. 
 From a code efficiency point of view, producing a lazy something and then 
immediately evaluating it is inefficient.  It is better to use a strict 
version of the something in the first place.  Does Clojure provide strict 
versions of things like concat, or would I need to roll-my-own?

Thinking again of efficiency... I had a go at doing an 
accumulator-passing-style (APS) version of flatten.  Here it is...

(defn my-apsbased-flatten
  [xs]
  (letfn [(my-flatten-aps [xs avec]
(if (nil? xs)
  avec
  (let [x (first xs), ys (next xs)]
(if (sequential? x)
  (recur ys (into avec (my-flatten-aps (seq x) '[])))
  (recur ys (conj avec x))]
(seq (my-flatten-aps (seq xs) '[]

This is more efficient (I think) than my earlier cps-based flatten.  But it 
has the problem again of using the stack via the non-recur call to 
my-flatten-aps.

I'm wondering if it's somehow possible to modify this aps implementation to 
also use trampolining?

Alternatively, maybe there's a combination aps-cps variation which can be 
trampolined??  I've had a bit of a go at this and so far can't see how to 
do it.  Perhaps not, as APS seems to do pre-calculation whereas CPS seems 
to do post-calculation?

But I can't help thinking that there must be a more efficient trampolined 
version of flatten that utilizes the structure of the "flatten problem" 
more, like APS does?

Cheers,

Mark.

On Tuesday, 15 July 2014 19:25:26 UTC+9:30, puzzler wrote:
>
> Yes, here's the trampolined version which won't stack overflow:
>
> (defn my-flatten
>   [xs]
>   (letfn [(my-flatten-cps [xs k]
> (if (nil? xs)
>   (k '())
>   (let [x (first xs), ys (next xs)]
> (if (sequential? x)
>   (recur ys (fn [v] (fn [] (my-flatten-cps (seq x) (fn [w] 
> (fn [] (k (doall (concat w v)
>   (recur ys (fn [v] #(k (conj v x]
> (trampoline my-flatten-cps (seq xs) identity)))
>
> Basically, you just wrap the body of each continuation in a function of no 
> arguments, and call the recursive function with trampoline.
>
> Another thing you have to do is wrap the concat in a doall, otherwise 
> you'll get a stack overflow when the deeply nested lazy concatenation is 
> realized.
>
>
> On Tue, Jul 15, 2014 at 12:13 AM, Mark P > 
> wrote:
>
>> I'm very new to continuation passing style (CPS), and as part of the 
>> learning process I've done a CPS version of a "flatten" function.  Ie, it 
>> does the same thing as the standard clojure "flatten", but is implemented 
>> using a recursive local CPS helper function.  I'm interested in comments / 
>> critiques on what I've done.
>>
>> Here it is...
>>
>> (defn my-flatten
>>   [xs]
>>   (letfn [(my-flatten-cps [xs k]
>> (if (nil? xs)
>>   (k '())
>>   (let [x (first xs), ys (next xs)]
>> (if (sequential? x)
>>   (recur ys (fn [v] (my-flatten-cps (seq x) (fn [w] (k 
>> (concat w v))
>>   (recur ys (fn [v] (k (conj v x]
>> (my-flatten-cps (seq xs) identity)))
>>
>> I'm relatively inexperienced with clojure, so please feel free to suggest 
>> improvements to my clojure code.
>>
>> But what I'm most interested in is understanding CPS better and about how 
>> it interacts with Clojure and with "recur".  As you can see, my-flatten-cps 
>> uses recur nicely to traverse at a breadth level.  But as we sink down into 
>> depth, I've done an actual non-recur call to my-flatten-cps.  I presume I 
>> can't do a recur here instead (because it would attempt to jump to the most 
>> immediate fn??) - is this correct?
>>
>> Is there any way around this?  (As I write this, the word "trampoline" 
>> comes to mind - some videos I've watched speak of this - but not sure how 
>> this would work and what efficiency trade-offs would be involved.)
>>
>> The other things is... is it so bad that it is not fully using recur - 
>> maybe using a bit of stack is okay??
>>
>> Thanks,
>>
>> Mark.
>>
>>  -- 
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clo...@googlegroups.com 
>> 
&

Critiques of "my-flatten" which uses CPS

2014-07-15 Thread Mark P
I'm very new to continuation passing style (CPS), and as part of the 
learning process I've done a CPS version of a "flatten" function.  Ie, it 
does the same thing as the standard clojure "flatten", but is implemented 
using a recursive local CPS helper function.  I'm interested in comments / 
critiques on what I've done.

Here it is...

(defn my-flatten
  [xs]
  (letfn [(my-flatten-cps [xs k]
(if (nil? xs)
  (k '())
  (let [x (first xs), ys (next xs)]
(if (sequential? x)
  (recur ys (fn [v] (my-flatten-cps (seq x) (fn [w] (k 
(concat w v))
  (recur ys (fn [v] (k (conj v x]
(my-flatten-cps (seq xs) identity)))

I'm relatively inexperienced with clojure, so please feel free to suggest 
improvements to my clojure code.

But what I'm most interested in is understanding CPS better and about how 
it interacts with Clojure and with "recur".  As you can see, my-flatten-cps 
uses recur nicely to traverse at a breadth level.  But as we sink down into 
depth, I've done an actual non-recur call to my-flatten-cps.  I presume I 
can't do a recur here instead (because it would attempt to jump to the most 
immediate fn??) - is this correct?

Is there any way around this?  (As I write this, the word "trampoline" 
comes to mind - some videos I've watched speak of this - but not sure how 
this would work and what efficiency trade-offs would be involved.)

The other things is... is it so bad that it is not fully using recur - 
maybe using a bit of stack is okay??

Thanks,

Mark.

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Style-question: self-named attribute getters?

2014-06-26 Thread Mark P
Thanks Ryan and James - that gives me a few more ideas on how to think 
about things.  Hopefully some of the links Ryan posted will clarify things 
for me also.

Ryan - yes my question about namespaces was to do with understanding the 
ideal granularity of namespaces.  And more specifically, whether it's a 
good idea to have a separate namespace for each data entity of interest (eg 
fruit), or whether it's better to use namespaces more sparingly.  I guess 
in part, I was using the namespace to group my getter functions, much like 
what a class name might do in an OOP language.  So again, wondering whether 
my C++ background is influencing me in the wrong direction here.

Cheers,

Mark.

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Style-question: self-named attribute getters?

2014-06-25 Thread Mark P
Thanks Ryan, Mike and James for your comments and info.  Ryan I will follow 
up the links you posted.

In the meantime, a request for some clarification...

I have read / watched clojure stuff along these lines... ie that data 
hiding (in an immutable data context) is bad.  I thought my approach was 
taking this into account.  Ie, I am actually using a hash-map for my fruit 
instance data (rather than say closures for true data hiding) and this is 
not hidden - it is freely accessible to users of my fruit library.  Users 
can choose to use getter functions or use more direct map access 
techniques.  The getter functions sort of provide self documentation about 
interface intent, without restricting/forcing users to be limited to this 
if the interface has weaknesses.  I guess I was trying to "take the best 
from both approaches".  But maybe you are telling me that even this 
watered-down-encapsulation is not good?

Ryan you are suggesting that maybe defrecord is the way to go.  I haven't 
read about that yet, so I will look into that.

But just suppose I wanted to stick with using raw hash-maps for my data. 
 Would you suggest that instead of my current approach, I should...

   - Not implement any getter function when a keyword accessor will do.  Eg 
   don't implement (defn color [fru] (:color fru)), just let library users do 
   (:color fru) themselves.
   - Do still implement other getters, eg (defn red? [fru] (= :red fru)) 
   and eg (defn packingvol [{:keys [size]}] (* size size size)).
   - What about "make"?  Do I still implement a fruit constructor function, 
   or do I leave it to users to use usual hash-map constructors?  (And if I 
   should not implement a fruit constructor, how do I indicate to users the 
   shape that a fruit hash-map should take?  Do I just document this in 
   comments?)
   - Was I right to construct a new namespace for my fruit-related data and 
   functions?

Thanks,

Mark.

On Thursday, 26 June 2014 11:42:01 UTC+9:30, Ryan Schmitt wrote:
>
> In object-oriented programming, encapsulation is always and everywhere 
> regarded as a highly significant design virtue, but the Clojure people have 
> a bit of a different assessment, particularly when it comes to information. 
> In one talk, Rich Hickey pointed out that encapsulation is for hiding 
> implementation details, but information doesn't *have* an implementation; 
> there are no innards to encapsulate *unless you add them*. Stuart 
> Halloway gave one talk where he made a brilliant point about how 
> abstraction is valuable for *commands*, because then it limits what you 
> have to know, but it's not valuable for *queries*, because then the 
> abstraction (i.e. the custom accessors that "encapsulate" your data) only 
> limits what you can perceive.
>
> And of course, there's Alan Perlis's old saw that "it is better to have a 
> hundred functions operate on one data structure than to have ten functions 
> operate on ten data structures"--that is to say, by using generic data 
> structures (e.g. maps) to directly represent information in your domain, 
> you can reuse all of the generic functions that operate on those data 
> structures, whereas encapsulated data screws your clients because it 
> renders all of their generic collections libraries useless. (This is one of 
> the ways in which OOP has failed to deliver on its promise of pervasive 
> code reuse.)
>
> Some of Rich Hickey's talks that touch on the subject:
>
> http://www.infoq.com/presentations/Value-Values
> http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey
>
> As for your particular example, I recommend looking at defrecord, which 
> generates a data structure that behaves like a map (it can be perceived and 
> manipulated generically), as well as various constructors and readers and 
> so forth for that type. defrecord also lets you specify protocols for your 
> data type. See:
>
> http://clojure.org/datatypes
>
> Also be sure to check out Prismatic's survey of Clojure's choices for 
> doing "object"-like things:
>
>
> https://github.com/Prismatic/eng-practices/blob/master/clojure/20130926-data-representation.md#data-types
>
> On Wednesday, June 25, 2014 6:34:50 PM UTC-7, Mark P wrote:
>>
>> I've only recently started real clojure development, so very much still 
>> learning what styles work and what don't.  I have a question about naming 
>> attribute getters...
>>
>> Suppose I want to model "fruit" entities.  I will use a hash-map to 
>> represent the data for each such entity, and will defn a "make" function to 
>> construct fruit instances.  I will put "make" and any other fruit-related 
>> functions within a new namespace &qu

Style-question: self-named attribute getters?

2014-06-25 Thread Mark P
I've only recently started real clojure development, so very much still 
learning what styles work and what don't.  I have a question about naming 
attribute getters...

Suppose I want to model "fruit" entities.  I will use a hash-map to 
represent the data for each such entity, and will defn a "make" function to 
construct fruit instances.  I will put "make" and any other fruit-related 
functions within a new namespace "myprog.fruit".

Because my data representation is a map, strictly speaking I don't need any 
attribute getter functions.  Because I could simply use the attribute 
keywords in the map as my getter functions, eg (:color fru).  But I will 
create actual getter functions within my namespace anyway, for a few 
reasons.

   1. It will signal to any users of my fruit library, which attributes are 
   "official" and are expected to be used / supported, versus attributes which 
   are more of an implementation detail.
   2. Some attributes will simply be (defn color [fru] (:color fru)), 
   whereas others are less direct, eg (defn red? [fru] (= :red fru)) or 
   another eg (defn packingvol [{:keys [size]}] (* size size size)).  
   3. Down the track I can change my data representation, and just 
   reimplement the getter functions.  Users of my fruit library who have stuck 
   to my getter functions interface will not need to change a thing.

This approach seems okay to me so far, though I am open to critiques and 
alternative suggestions.  But one issue has come to mind... leading to the 
question of this post...

At the end of 2. above, I have defined a local let symbol "size" as part of 
the map destructuring.  But it so happens I have already defined a size 
getter, namely (defn size [fru] (:size fru)).  So within the definition of 
packingvol my size getter is masked by the local symbol "size".  Now I'm 
not sure this masking causes much harm... I don't actually need to use the 
size getter here, and if I really needed it I could always use 
"myprog.fruit/size"...  But something still makes me feel uncomfortable 
about it, maybe because this masking could end up happening a lot within my 
fruit.clj source code file.

Now I could just switch to a new naming convention for my getters, ie 
"color-get", "red?-get", "size-get", "packingvol-get" etc.  But I'm not 
sure I like the extra verbosity.  And for users of my fruit library - who 
will be working in a different namespace - this problem mostly goes away as 
they will probably be namespace-qualifying access to my getters.

Is using self-named attribute getters a good idea?

Thanks,

Mark.

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Auto reloading of dependencies with cider

2014-06-23 Thread Mark P
Thanks Michael.  With a bit of updating and configuring I seem to have this 
working

For the benefit of other readers of this thread...  to get C-c C-x to work, 
it seems you still need to configure things properly for tools.namespace... 
see the links in Ralf's post above for details on this.

Also, I needed to upgrade to the latest version of cider (0.7.0) for the 
cider integration with refresh.

Cheers,

Mark.

On Monday, June 23, 2014 7:38:40 PM UTC+9:30, Michael Griffiths wrote:
>
> You can also use the `cider-refresh` command, which is bound to `C-c C-x` 
> by default. It uses tools.namespace.repl/refresh under the hood.
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Auto reloading of dependencies with cider

2014-06-23 Thread Mark P
Thanks Ralf.  This looks like exactly what I need.

On Monday, June 23, 2014 2:43:41 PM UTC+9:30, Ralf Schmitt wrote:
>
> Mark P > writes: 
>
> > What do other people generally do here?  I suspect there is a 
> commandline 
> > way of getting lein to do this for me.  Is that what people do?  Or do 
> > people just make sure they do "C-c C-k" in each relevant buffer?  (But 
> > isn't this error prone - ie if you forget to do this in some buffer that 
> > you've changed?) 
>
> Take a look at tools.namespace [1], which handles reloading your 
> namespaces. Also please read 
> http://dev.solita.fi/2014/03/18/pimp-my-repl.html. 
>
> [1] https://github.com/clojure/tools.namespace 
>
> -- 
> Cheers 
> Ralf 
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-22 Thread Mark P

>
> Okay. Functions as values. Go look at the IFn interface, 
>
> https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java. 
>
>

Thanks for the link - this helps!  When the clojure compiler generates a 
class type that conforms to this interface, does it generate a .java file 
which is then compiled using the java compiler?  I am guessing not.  I am 
guessing that clojure knows how to generate a byte code version of a class 
type directly.
 

> In C or C++ you can take a raw machine pointer to a function. The JVM 
> does not allow for this behavior the result of which is that whenever 
> you have a "function" really what you have is a function-like object 
> with the standard application/invocation member methods.


Thanks for explaining.  This sounds very much like a C++ functor.

For the record, the raw-pointer-to-function is the old-school thing to do 
in C++.  These days functors are often used - object types that have the 
function application operator defined (which is a method with special 
function application syntax) - because these are more powerful (eg 
templated methods allowing compile-time polymorphism) and allow for better 
performance (eg inlining of code).  So it sounds like what clojure does 
under-the-hood is to more-or-less define a functor type at compile time and 
then do various instantiations at run time.
 

> The "standard" Clojure compiler is pretty braindead when it comes to the 
> emitted bytecode, but this is due to the philosophy (backed up by 
> experience) that the JIT is typically good enough.


Good to know - thanks!  This makes things clearer for me.
 

> You could generate 
> better code, and my GSoC project is research into doing so but the 
> reality of Clojure programs is that function calls even with Var 
> indirection are free in comparison to the performance hits we take due 
> to using immutable datastructures and eschewing in place updates. 
>
> Reid  
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Auto reloading of dependencies with cider

2014-06-22 Thread Mark P
I am fairly new to using cider.  Initially I put all my code into my 
core.clj file that lein created for me.  But now I am splitting my file up 
into multiple clj files and using things like:

(ns myprog.core
  (:use [myprog.milk :as milkx :only []])
  (:use [myprog.cheese.brie :as briex :only [brielist]])
  (:use [myprog.cheese.cheddar :as chedderx :only [chedderlist]])
  (:gen-class))


to pull in definitions from other clj files into my core.clj.

This seems to be working well enough, except that, doing "C-c C-k" (ie 
cider-load-current-buffer) no longer always loads everything.

It seems to auto load all the other clj files the first time.  But when I 
make changes in these other files (which I save), these are not seen after 
doing a "C-c C-k" in core.clj.  It seems that I need to explicitly go to 
each buffer with a modification in it and do "C-c C-k" in each one.  Then I 
can do "C-c C-k" in the main buffer and all the changes will be seen.

I can cope with this, but it would be nice to be able to give a command in 
the core.clj buffer which effectively does "load core.clj and recursively 
reload any dependency buffers/files".  (Even better would be if it only 
reloaded those files/buffers which had changed since the last load.)

What do other people generally do here?  I suspect there is a commandline 
way of getting lein to do this for me.  Is that what people do?  Or do 
people just make sure they do "C-c C-k" in each relevant buffer?  (But 
isn't this error prone - ie if you forget to do this in some buffer that 
you've changed?)

Thanks,

Mark.



-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-21 Thread Mark P

>
> A toy project I've worked intermittently on makes heavy use of *partial* 
> to dynamically build complex functions.  I wish that *partial* was smart 
> enough to recompile its first argument, maybe taking advantage of whatever 
> type inference the compiler can make, but partial 
> 
>  
> only returns a function wrapper.  Ohwell.
>

This raises a different question with me...  Does clojure have the same 
scope for code optimization that other languages, eg C++, have?  Ie, even 
though a C++ compiler has to deal with all sorts of complicated syntax, it 
is able to perform a whole lot of at-compile-time optimizations based on 
the C++ semantics.  Is the clojure compiler free to do a similar thing?  Or 
is it bound to adhere to the straightforward evaluation rules?

My understanding is that one of the roles of macros is to perform 
at-compile-time optimizations.  Sometimes a macro can do something clever 
to transform less performant code into optimized code.  But is this the 
only way of improving compiled code - ie introducing code-optimizing macros 
- or does the clojure compiler itself have scope to elide certain things 
and make other performance optimizations?

I know the java JIT optimization reduces the need for this, but my guess is 
that there is still a role for at-compile-time code optimization.

Cheers,

Mark.

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-21 Thread Mark P

>
>
> What's the reason for asking? If you aim for making efficient code (that 
> is running very many times in tight loops), I think most of this will be 
> inlined by the JIT, as long as it is not confused by side effects and other 
> things.


I'm asking mostly because I want to better understand the essence of how 
clojure works.  But you are right in thinking that I am also interested in 
better understanding performance implications - but this is a secondary 
reason.  Primarily, I'm just trying to understand better.

Coming from a C++ background I'm not that familiar with functions as first 
class values.  We sort of do have them in C++ - as functors - ie a class 
that has the function invocation operator defined.  This class can have 
storage as well, which means you can have a functor object type which then 
can have particular instances instantiated with different particular 
parameters stored with the object instance.

I'm wondering whether this is effectively what Clojure does under-the-hood, 
or whether it does something different / more sophisticated.
 

>
> As long as the JVM can optimize the procedure, it's of lesser importance 
> how Clojure solves it in "one-shot" scenarios.
>

In one sense yes, though it's nice to better understand what is happening 
and how this influences program performance.
 

>
> Maybe I somewhat dodge the question, but dynamic just in time compilation 
> is so mindblowing cool that an hypothesis about the quickest possible way 
> to solve the problem combined with profiling is what matters most in 
> practice.
>
> /Linus
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Understanding when compilation occurs - for function producing functions

2014-06-21 Thread Mark P

>
>
>> ​Well, you misunderstand it, as far as I know, clojure treat all fn as 
> object, so in your adder-maker example, clojure compiled two fn as object, 
> that's adder-maker itself and anonymous function it returns.
>

You must be right.  As far as I know, the compiler is only called as part 
of eval, and I don't think eval would be called every time a function wants 
to produce a resultant function at run time.

I guess what I'm trying to understand then, is how the maker function can 
produce a compiled function object when it doesn't know all the details of 
the function until runtime (the m parameter in this case).
 

> The compiled add-maker is just instantiate that anonymous with `m`, and 
> return it. So (adder-maker 1) will produce that instantiated anonymous 
> function, and since it's a function and it's in the first position of list, 
> clojure will invoke it with 2, and that anonymous function will do actual 
> computation.
>

So maybe what is happening underneath is...  When the function maker 
function is compiled, it creates a java object type corresponding to the 
anonymous function.  This object type includes both an invocation member 
(taking one argument, n) and storage for m.  Then at run time when this 
function is needed for a particular m (in this case 1), an instance of the 
java object type is created, with m set to 1.

That's what I am guessing anyway.

What this does mean though I guess is that the code can't be optimized to 
take advantage of the specific case of m being 1 (eg low level using an inc 
instruction on n rather than explicitly adding 1 to it).

But maybe this is where JIT optimization comes into play - maybe this 
optimization can happen here?

Thanks for your reply.

Cheers,

Mark.

P.S. I still wonder whether the clojure compiler itself could do some kind 
of mini-compile when at-runtime producing a function.  I guess it would be 
hard for the compiler to know whether the mini-compile was warranted or not.
 

>
> functions are compiled at once when clojure reader meet them, and 
> invocation is just the matter of instantiate.
>
> Thanks,
> Di Xu
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Understanding when compilation occurs - for function producing functions

2014-06-19 Thread Mark P
Suppose at my REPL I do...

(defn direct-report-oneplustwo [] (println (str "Direct one plus two is " 
((fn [n] (+ 1 n)) 2) ".")))

...then I presume that the compiler has compiled my 
direct-report-oneplustwo function, and that this has included compilation 
of my anonymous function (fn [n] (+ 1 n)).  So that now if I run...

(direct-report-oneplustwo)

...at my REPL it just needs to run this precompiled code to tell me my 
answer 3 - no additional compilation required.

So far so good.

But what if instead I do this at my REPL...

(defn adder-make [m] (fn [n] (+ m n)))

(defn indirect-report-oneplustwo [] (println (str "Indirect one plus two is 
" ((adder-make 1) 2) ".")))

...Now at this point, both adder-make and indirect-report-oneplustwo should 
have been compiled.  But unlike our first approach, the anonymous function 
(fn [n] (+ 1 n)) has not yet been created by (adder-make 1) and so 
presumably (??) has not yet been compiled??

I am presuming that it is only when we actually run the report function...

(indirect-report-oneplustwo)

...that (adder-make 1) is actually run, thereby producing the anonymous 
function (fn [n] (+ 1 n)), which then gets compiled right then-and-there, 
immediately followed by its execution??

But maybe this is wrong!?  Maybe instead somehow the compiler managed to 
"pre-compile" the anonymous function as part of the compilation of 
adder-make?  Maybe there is a stored compiled "template" function, the 
bytecode for which gets "rolled out" at runtime in slightly different ways 
depending on the parameter m??

Can anyone clarify for me what happens here?

Thanks,

Mark.

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: fn and let are special forms or macros?

2014-06-18 Thread Mark P
Wonderful - thanks Andy!

On Thursday, June 19, 2014 12:40:24 PM UTC+9:30, Andy Fingerhut wrote:
>
> user=> (source special-symbol?)
> (defn special-symbol?
>   "Returns true if s names a special form"
>   {:added "1.0"
>:static true}
>   [s]
> (contains? (. clojure.lang.Compiler specials) s))
> nil
>
> user=> (keys (. clojure.lang.Compiler specials))
> (& monitor-exit case* try reify* finally loop* do letfn* if 
> clojure.core/import* new deftype* let* fn* recur set! . var quote catch 
> throw monitor-enter def)
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: fn and let are special forms or macros?

2014-06-18 Thread Mark P
Interesting - thanks!

Looks like doing `symbol is a good way of telling whether something is a 
special symbol or not.  If syntax-quote results in namespace-qualification 
it then it *is not* special (with the exception of import*); if it does not 
namespace qualify it, then it *is* special.

Previously I've been using the fact that (source symbol) comes up with 
"Source not found" to indicate that a symbol might be special.  But not 
sure how reliable this method is.  I imagine there might be other 
situations where the source code cannot be found.

Cheers,

Mark.

On Wednesday, June 18, 2014 6:26:04 PM UTC+9:30, Ambrose Bonnaire-Sergeant 
wrote:
>
> Hi Mark,
>
> Here's a brief doc on special forms: 
> http://clojure-doc.org/articles/language/macros.html#special-forms-in-detail
>
> Thanks,
> Ambrose
>
>
> On Wed, Jun 18, 2014 at 12:13 PM, Mark P > 
> wrote:
>
>> Thanks Tassilo for the explanation - much appreciated!
>>
>> I have been searching the web and searching clojure text books for the 
>> last two hours trying to find the answer to this same question.  Finally I 
>> stumbled onto this thread!
>>
>> I realize that hiding the complexity of distinctions between fn / fn* and 
>> let / let* etc might make the documentation more accessible for some users, 
>> but for others (like me and presumably also Plínio) it makes it really hard 
>> to track down what is *really* going on.  I wish this distinction was part 
>> of the formal documentation.
>>
>> Does anyone know of documentation anywhere that does include these kinds 
>> of distinction?
>>
>> Thanks,
>>
>> Mark.
>>
>> On Thursday, 6 March 2014 02:27:26 UTC+10:30, Tassilo Horn wrote:
>>
>>> Plínio Balduino  writes: 
>>>
>>> Hi Plínio, 
>>>
>>> > Clojure.org says fn and let are special forms, but using the macro 
>>> > sourceshows that both are macros calling fn* and let* respectivelly. 
>>> > 
>>> > So fn and let are "special special forms", or clojure.org is 
>>> > incorrect/outdated? 
>>>
>>> Well, they are correct from a user's point of view.  One never uses the 
>>> real special forms fn* and let*. 
>>>
>>> > If fn and let are really special forms and not macros, could you 
>>> > explain why? 
>>>
>>> fn and let (and also loop) are macros around the real special forms fn* 
>>> and let* (and loop*) that add support for destructuring.  For example, 
>>>
>>> (let [[a b] [1 2]] 
>>>   (+ a b)) 
>>>
>>> expands to 
>>>
>>> (let* 
>>>   [vec__8592 [1 2] 
>>>a (clojure.core/nth vec__8592 0 nil) 
>>>b (clojure.core/nth vec__8592 1 nil)] 
>>>   (+ a b)) 
>>>
>>> where the destructuring has been transformed to "normal" code already. 
>>>
>>> Bye, 
>>> Tassilo 
>>>
>>  -- 
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clo...@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+u...@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 unsubscribe from this group and stop receiving emails from it, send an 
>> email to clojure+u...@googlegroups.com .
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: fn and let are special forms or macros?

2014-06-17 Thread Mark P
Thanks Tassilo for the explanation - much appreciated!

I have been searching the web and searching clojure text books for the last 
two hours trying to find the answer to this same question.  Finally I 
stumbled onto this thread!

I realize that hiding the complexity of distinctions between fn / fn* and 
let / let* etc might make the documentation more accessible for some users, 
but for others (like me and presumably also Plínio) it makes it really hard 
to track down what is *really* going on.  I wish this distinction was part 
of the formal documentation.

Does anyone know of documentation anywhere that does include these kinds of 
distinction?

Thanks,

Mark.

On Thursday, 6 March 2014 02:27:26 UTC+10:30, Tassilo Horn wrote:
>
> Plínio Balduino > writes: 
>
> Hi Plínio, 
>
> > Clojure.org says fn and let are special forms, but using the macro 
> > sourceshows that both are macros calling fn* and let* respectivelly. 
> > 
> > So fn and let are "special special forms", or clojure.org is 
> > incorrect/outdated? 
>
> Well, they are correct from a user's point of view.  One never uses the 
> real special forms fn* and let*. 
>
> > If fn and let are really special forms and not macros, could you 
> > explain why? 
>
> fn and let (and also loop) are macros around the real special forms fn* 
> and let* (and loop*) that add support for destructuring.  For example, 
>
> (let [[a b] [1 2]] 
>   (+ a b)) 
>
> expands to 
>
> (let* 
>   [vec__8592 [1 2] 
>a (clojure.core/nth vec__8592 0 nil) 
>b (clojure.core/nth vec__8592 1 nil)] 
>   (+ a b)) 
>
> where the destructuring has been transformed to "normal" code already. 
>
> 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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Future of performant software: cores or memory?

2014-01-01 Thread Mark P
I have watched a number of clojure talks where the concurrent programming 
benefits of Clojure are emphasized.  People have suggested that the number 
of cores in computers is growing with an exponential trend.  Software 
developers will need programming techniques (eg immutable functional 
programing) which allow full harnessing of this.  Software that doesn't 
utilize the cores will not perform well and will be left behind.

But I have heard counter arguments to this view of the future...

   1. The number of cores isn't growing very fast.
  - There isn't much demand for more cores, so this growth will be very 
  slow for most computer devices.
  2. Memory performance is the key at this time.
  - Whereas raw CPU speed previously was growing dramatically for many 
  years, this has never been true for memory speed.  As a result, memory 
  access accounts for a high percentage of execution time in modern 
software.
  - The key to writing performant software at this time (and for many 
  years to come) is to concentrate primarily on good memory performance. 
   This means...
 - Keep memory footprint of programs small.
 - Use various techniques to minimize cache misses.
  - I have heard claims that dramatic program performance improvements 
  may be achieved by concentrating on these memory considerations.
  - It is claimed that for the next 5 or 10 years, there will be much 
  more performance yield to be had by concentrating on memory 
optimizations, 
  than to concentrate on growth in the number of CPU cores for performance.
  - Yes utilize the multiple cores where appropriate, but only in 
  simple ways.  More focus should be given to performant memory usage 
within 
  each thread, than worrying about deeply entwined multi-threaded 
programming.
  - Languages like C/C++ allow for good memory optimizations much 
  better than Java.  And in Clojure, it sounds like it is harder again.
   
There is a lot that I like about Clojure, but is it unsuitable for software 
where performance will be important into the future?

Or will the increase in multi-core capabilities soon mean that memory 
performance limitations pale into insignificance compared with the 
computational gains achieved through Clojure techniques for effectively 
utilizing many cores?

Or is it possible to improve memory performance (eg reduce cache misses) 
within Clojure?

Thanks,

Mark P.

-- 
-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Funding Clojure 2010

2009-12-14 Thread Mark P
> This strikes me as a potentially disastrous idea; look at how much
> mindshare going the proprietary route has cost Rebol, for instance.

I don't know anything about Rebol except for some quick
googling that I've just done on them.  But the impression
I get is that what they've done is substantially different
from the Plan B that I've proposed.

>From what I can tell, there is no guarantee that the current
Rebol code base will ever become open source.  The Plan B
proposal guarantees that after 1 year (or whatever time
period is chosen) the current code base will become open
source.

One of the big pluses of open source - in my view - is the
long term guarantees it provides for the code base.  If Rich
ever dropped Clojure development, open source means that
everyone would still be freely allowed to use, maintain and
further develop the code base.  Plan B still provides this.  As
a worst case it merely delays this.

I am not saying Plan B is the ideal choice.  The two main
issues with it, I think, are:

  * it means administering two versions; and
  * it means some restriction of its use.

So I prefer what Rick has proposed - if it can be made to
work.  But if it doesn't, I can't think of a better choice than
Plan B, although the "work for Sun/Company-X" option that
BerlinBrown suggested might work if the right job offer
came along.

If Plan B were implemented in a reasonable way, with
licence fees not unreasonable and with open source
guarantees not too far away, then surely the goodwill
would remain - especially if it were essential for the survival
of the project.  And if goodwill remains, and guarantees
remain, surely mind-share would remain???

-- 
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: Funding Clojure 2010

2009-12-14 Thread Mark P
I very much hope your voluntary donation approach works.  I
suspect the best chance of making it work is if you regularly
remind-people-of/market/promote the idea of donating.  That is,
I believe there is a lot of goodwill out there, and a lot of people
will have good intentions, but it is easy for these good intentions
to not translate into actual donations.  Of course, there needs to
be a healthy balance between promoting the idea enough and
doing it so much that people get annoyed.  But I think it should
be possible to get the balance right.

Hopefully the donation approach is a success, but if not, may I
suggest a Plan B.  And that is that at any point in time you have
two versions of Clojure going:

  * a proprietary version of "the latest and greatest"; and

  * an open source version which is "1 year old" (or something
like that).

Each proprietary release would include in the licence "from date
XX/XX/ and onwards, this release may be used under the
open source licencing terms ...".  This would give proprietary users
the guarantee that at some point the version of clojure they are
using would become open source.

Proprietary users would be paying for the ability to use the latest
and greatest.  If the licence fee were reasonable, then this, together
with the goodwill factor, I hope would be enough to get people to
finance the project.

This approach seems to me to be a good compromise between
open source and proprietary funding.  It provides all the benefits of
open source over time, yet provides a tangible reason for paying
licence fees beyond just goodwill.  It also means that employees
who are part of businesses that can't understand voluntary donations,
can more easily justify the expenditure.

Don't get me wrong, I think the voluntary donation model is the best
one - if it works - and so is worth a shot.  But if it doesn't work
out,
I offer this alternative model as one that might be worth considering.

Cheers,

Mark P.

-- 
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: when performance matters

2009-01-13 Thread Mark P

> A macro cannot depend on runtime information. A macro is a function  
> that is called at compile time, its argument is an expression (as  
> written by the programmer, or as returned by another macro), and its  
> result is a modified expression. There is no way a macro could access  
> runtime information. It is a program that works on program code, not  
> on runtime data.

Then what do people mean when they say that lisp blurs
the distinction between compile-time and run-time?  I
thought that "macros executing at runtime" was part
of this.  But if not, I don't know what they do mean.

I thought macros could get executed at runtime as
follows.  Suppose I have a domain-specific-language
implemented in a lisp, using macros.  Suppose at
runtime some of this domain-specific-code gets
generated somehow (code is data at this point).
An "eval" is executed on this domain-specific-code,
which causes the macros (used to implement the
domain-specific-language) to transform the input
code at runtime.

Is this wrong?

I also thought that when a "clojure application" is
bundled up as java bytecode, this "executable"
actually includes the clojure compiler.  Why would
this be included if compilation (including macros)
is never performed at runtime?

Is there something fundamental I am not
understanding?

Thanks,

Mark P.

--~--~-~--~~~---~--~~
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
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: when performance matters

2009-01-13 Thread Mark P

On Jan 13, 5:49 pm, Zak Wilson  wrote:
> You're probably thinking of 
> this:http://www.flownet.com/gat/papers/lisp-java.pdf

Thanks for the link.

> There's also the (in)famous language benchmark
> site:http://shootout.alioth.debian.org/

This is primarily what I was going on.  I realize no
benchmarking approach is going to be perfect, but
this attempt doesn't seem too bad.  Is there any
reason to be particularly sceptical about results
found here?

Oh, and I realize my comments about SBCL lisp being
3 to 4 times slower than C++ only apply for the quad
core machines.  The single core machines have SBCL
as 2.2 or 2.3 times slower than C++.  Perhaps this
is a truer representation of SBCL's "raw capabilities".

But a 120% performance hit is still quite a whack.

Cheers,

Mark P.

--~--~-~--~~~---~--~~
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
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: when performance matters

2009-01-13 Thread Mark P

> I am not aware of any auto-parallelizing compiler that is actually  
> useful in practice.

Good to know - thanks.

> > And this leads to another question I have about Lisp-style
> > languages in general.  I get the impression that in Lisp
> > much of the "compiler" is Lisp code itself.  Ie, layer and
> > layer of macros build up towards the language that then
> > actually gets "used".  Does this layer upon layer of macros
> > lead to inefficiencies in itself?  Or is the opposite true?
>
> Macros are handled at compile time, so they add no run-time overhead.

But isn't "compile time" sometimes _at_ runtime?  Ie, if
a macro is dependent on runtime information, then isn't
it passed to "the compiler" which is included as part of
the runtime executable, turned into bytecode, and then
executed itself.  That's how I thought it worked anyway.
In which case, compiler efficiency is of importance.

> There are efficient real-life libraries that use this approach. The  
> best known is probably FFTW, which consists of optimized C code  
> generated by functional OCaml code. I have no doubt that Clojure  
> could take the role of OCaml there. Of course, writing such an  
> optimizing library requires a significant effort.

Thanks for the example.  It's good to know what is
possible.

Cheers,

Mark P.

--~--~-~--~~~---~--~~
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
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: when performance matters

2009-01-12 Thread Mark P

On Jan 13, 1:21 am, Stuart Sierra  wrote:
> If you have
> highly-optimized, custom-designed numerical algorithms written in a
> low-level language like C++, you will never be able to write a version
> that is equally fast in a dynamic, virtual-machine language.

I think you are essentially right (although some optimizations
can only be performed with runtime information).  But highly-optimized
low-level code is very rigid.  It is difficult to maintain it and
adapt it
to changing program needs and new technology (with different
optimization characteristics).

So I am willing to wear a certain loss of performance in exchange
for a more agile program, but not too much.  I think I'd be willing
to wear a 20% loss in performance (perhaps even 50%), but not
magnitudes much higher than this.  And my gut feeling is that
20% or so should be achievable for a lisp-style language.  But the
Clojure+JVM solution sounds like it is still a way off from this.

> Compilers are smart, but they are not that smart.

I am a relative newcomer to lisp, but my impression is that
lisp should be thought of as both low level and high level
all in one.  Ie, that the leverage from lower levels to higher
ones happens primarily via macros... which the programmer
has direct access to.  So in theory a developer could use
macros to perform compiler-style optimizations within
lisp itself, except these optimizations could be tailored
to the particular application.  So as long as the base level
lisp was implemented efficiently, the whole top-level
lisp program could be efficient.  But from what I can tell,
even the best lisp compilers produce slow code.  Even
SBCL lisp seems to be 3 to 4 times slower than C++.
So I must be misunderstanding something.  I can't see
why lisps should be inherently so slow.

> That being said, experience is the only reliable guide. If you want to
> know if Clojure will work for your job, the only thing to do is try
> it.

Yes, I think some experimental coding might be in order.  But
I'd like to get as much a grip on the performance landscape as
I can beforehand.

Thanks for tempering any over-enthusiasm and giving me your
best honest assessment.

Cheers,

Mark P.

--~--~-~--~~~---~--~~
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
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: when performance matters

2009-01-12 Thread Mark P

> JNA might be an alternative to JNI:https://jna.dev.java.net/
> But I wouldn't know; haven't used either.

Thanks for this info.  It sounds like JNA may be worth
looking into.

Cheers,

Mark.

--~--~-~--~~~---~--~~
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
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: when performance matters

2009-01-12 Thread Mark P

> It all depends on your algorithms and your code. Clojure has lots of  
> support (data structures and algorithms) for concurrent programming,  
> but you have to choose and combine them yourself to get efficient  
> parallelization.

I know that there are other functional approaches where
the compiler automatically finds ways to parallelize.  Is there
much scope for this in Clojure?  Or is it all pretty much
manually added concurrency?

And this leads to another question I have about Lisp-style
languages in general.  I get the impression that in Lisp
much of the "compiler" is Lisp code itself.  Ie, layer and
layer of macros build up towards the language that then
actually gets "used".  Does this layer upon layer of macros
lead to inefficiencies in itself?  Or is the opposite true?

> Again this depends a lot on what you are doing. Hotspot is already  
> doing an impressive job on some applications, but remains bad at  
> others.

That seems to match what I've read.  On average I get the
impression that it is about 2 times as slow as efficient C++ code
and uses maybe 10 times as much memory.

What I'm wondering is whether there is still quite a bit of
"fat to be trimmed" with HotSpot, or whether it's approaching
the limits of what is achievable.

> One source of hope for better interfaces is new virtual machines. One  
> candidate is VMKit (http://vmkit.llvm.org/), an implementation of the  
> JVM (and .Net as well) on top of LLVM. Combine this with the gcc  
> version that produces LLVM code, and it should be possible to get  
> Java-C interoperability with much less friction than through the JNI.  
> On the other hand, it will be a long time before VMKit matches the  
> performance of HotSpot.

Thanks for the info!  This does sound like a promising
approach.  For the future though.

> You could also consider writing Clojure code that generates C++ code.  
> Or C, or why not directly LLVM.

Thanks.  Worth considering.  Though I don't really know
whether this is a practical option or not.  Maybe it is.


Thanks Konrad for your thoughts.  Most useful.

Cheers,

Mark P.

--~--~-~--~~~---~--~~
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
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
-~--~~~~--~~--~--~---



when performance matters

2009-01-11 Thread Mark P

I have recently found out about Clojure and am
rather impressed.  I am seriously considering
whether Clojure is a viable language for use at
work.  The main stumbling block would be if
performance (both speed and memory) turns out
to be insufficent.  I currently use C++, but I'd love
to be able to leave C++ behind and use Clojure
(or similar) instead.

The programs I write perform applied mathematical
optimization (using mainly integer arithmetic)
and often take hours (occasionally even days)
to run.  So even small percentage improvements
in execution speed can make a significant
practical difference.  And large problems can use
a large amount of memory - so memory efficiency
is also a concern.

Given these performance considerations, at first
glance Clojure does not seem like a good choice.
But I don't want to give up on the idea just yet.
The allure of modernized lisp-style programming
is really tempting.

There are three key factors that still give me
hope:

1. Some of the algorithms I use have the potential
to be parallelized.  I am hoping that as the number
of cores in PCs increase, at some point Clojure's
performance will beat C++'s due to Clojure's
superior utilization of multiple cores.  (Any ideas
on how many cores are needed for this to become
true?)

2. The JVM is continually being improved.  Hopefully
in a year or two, the performance of HotSpot will be
closer to that of C++.  (But maybe this is just
wishful thinking.)

3. Maybe I can implement certain performance critical
components in C++ via the JNI.  (But I get the impression
that JNI itself isn't particularly efficient.  Also, the more
I pull over into the C++ side, the fewer advantages to
using Clojure.)

If all else fails, maybe I could use Clojure as a prototyping
language.  Then when I get it right, I code up the actual
programs in C++.  But probably a lot would get lost in
the translation from Clojure -> C++ so would it be worth
it?

I'd love to be convinced that Clojure is a viable choice,
but I need to be a realist too.  So what do people think?
How realistic are my three "hopes"?  And are there
any other performance enhancing possibilities that I
have not taken into account?

Thanks,

Mark P.

--~--~-~--~~~---~--~~
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
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: update in place for unique references

2009-01-09 Thread Mark P

Hi Stuart,

> I think the big strength of Clojure is how easy it is to integrate
> Java code. If you have some performance-critical code you can always
> drop down to Java. Certainly, performance is important to Clojure, but
> I think the assumption is that it will never compete with pure Java on
> speed.

Yes you are right, the ability to drop down to Java is a plus.

But a unique reference approach in theory would be better
still as it allows one to maintain purity (referential transparency
and theoretically equivalent to no mutation) while under-the-hood
getting the efficiency of update-in-place.

But as I've discovered through this thread, the limitations of the
JVM might make this "sweet spot" somewhat smaller than I
would have liked.

Cheers,

Mark P.

--~--~-~--~~~---~--~~
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
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: update in place for unique references

2009-01-09 Thread Mark P

Hi Tim,

I appreciate your comments.

> It is possible to achieve this behavior explicitly if you really
> wanted to:
> (defn create-add-2 []
>   (with-local-vars [x 1]
>     (do
>       (var-set x 1)
>       (var-set x (inc @x))
>       (let [z @x]
>         (fn [y] (+ y z))

That's true.  Only the "(inc @x)" isn't update-in-place.  Presumably
some java something could be used here instead to get true update
in place.

> Such an aggressive optimizer might be unhappy with a runtime check and
> opt for an unsafe mutable:
> user=> (def p (java.awt.Point. 0 0))
> #'user/p
> user=> p
> #
> user=> (.setLocation p 1 2)
> nil
> user=> p
> #
> But might still be unhappy with having to use object calls, at which
> point I don't think Clojure is the right language. However lucky for
> them they could still go away and implement an incredibly efficient
> java api and call it from within Clojure very easily. They would still
> want to wring the last few drops of performance and write it in C.
> Actually they could still invoke that code at a high level via JNI but
> of course would want to keep the calls to a minimum to avoid calling
> overhead.

What you're saying could well be true.  Ie a runtime check of
unique reference might not be acceptable where performance
is a major concern.  But there are two ways around this.

1. Have the ability to turn runtime uniqueness checking on or off.
This way code can be tested with the check on, but then run
with it off once we are convinced the code is correct (at coder's
own risk of course).

2. Take up Mark Fredrickson's suggestion of a code walking
analysis macro to prove uniqueness before running the code.
That way no runtime check is needed.

The fact that java method calls are always expensive is still
a problem though.  As you say, ultimately a call to a C or C++
routine via JNI might be the only real performance answer.

I wish there were a better way.

> I'm just an observer, but if I can't see such a feature appealing to
> "the performance user" because it wont ever be as fast as they want it
> to be. To appeal to the general user transparent implementation, which
> it can't be if you want to preserve all the features. A subset between
> these exist, but is quite small and not a far step from moving up or
> down.

You might be right here, though I still feel uniqueness is a
good tool for writing safe and somewhat transparent "equivalent to
mutation" based code.  C++ is (unfortunately) my current main
language and I use a runtime uniqueness framework to ensure
much more reliable mutation based code there.  But I think Java's
insistence on virtual function calls may make a highly efficient
uniqueness approach difficult to achieve in Clojure.

> >   * uniquely-referenced (arbitrary mutation changes effectively
> >     allowed, but only ever referred to uniquely (runtime enforced)).
>
> I think that pretty accurately describes C++, its not fun debugging a
> runtime enforced coredump full of crap. :)
> I know that's not what your proposing sorry but I couldn't resist the
> analogy! I'm not saying its a bad idea, I just don't find it
> compelling to me personally.

But adhering to a uniqueness discipline within C++, together with
a functional approach like FC++, does lead to more reliable
and more transparent (and somewhat efficient) C++ code.  And
uniqueness in a lisp language should be much more elegant
than my C++ implementation.

But I think you and Mark Fredrickson are right to point out that
limitations within the JVM itself may make efficiency via
uniqueness that is competative with C/C++, impossible to
achieve.  I'm still hopeful there may be a way, but I can't see
it just now.

Cheers,

Mark P.

--~--~-~--~~~---~--~~
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
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: update in place for unique references

2009-01-08 Thread Mark P

Hi Mark F,

Thanks for your responses.

> 1. Data: Is this really a problem that is slowing down Clojure
> programs in practice? Can you provide some data to that effect? I
> would suggest writing a couple of Java benchmarks - one that updates a
> simple structure in place and one that only creates new data. Time
> them. Write more benchmarks, but this time do it in Clojure (though
> perhaps with some straight Java calls to make the updates). Are there
> differences in the Java versions from the Clojure versions? Are there
> differences in the update vs new data versions?

Writing some test code is not a bad idea, but from what I
heard Rich Hickey say in his online talks, probably unnecessary
to establish that using Clojure built-in data structures
involves a performance hit (in the single-thread case anyway).
I got the impression that Clojure structures are somewhere
in the range of 1.5 to 4 times worse than mutation based
structures.  Of course, this performance is quite an achievement,
given the advantages of Clojure's approach.  But for applications
which are performance critical, I am wondering whether
a uniqueness-based update-in-place would offer a
complementary well performing alternative.

> 2. Take a page from the Scheme playbook. Don't ask the language to
> implement this feature, ask for the minimal set of tools that you need
> to implement it. I would think a code walking escape analysis macro
> could be very useful. Instead of run-time reference counting, the
> macro could find data that is guaranteed not to escape its scope via a
> closure (e.g. let bound locals that are not used in any (fn
> [] ...)s ). What would you need access to? Additional JVM byte-code
> instructions? Post-compile processing by user code? Update in place
> methods for the normally immutable types?  I don't know exactly what
> you'd need, but ask for that before asking for a much bigger feature.

The escape analysis macro sounds interesting.  But an initial approach
might be, for each of these new data structures (mutation based under
the hood) to have two versions of each structure:

  * immutable (ie no more changes will ever occur - if you want a
modification you will have to make a full copy); and

  * uniquely-referenced (arbitrary mutation changes effectively
allowed, but only ever referred to uniquely (runtime enforced)).

Most structures of this type would start life as a uniquely-referenced
structure (either empty or a copy of an immutable), and have
lots of mutations effectively applied to them in a safe environment,
until they are ready to be "frozen" and released to the world as
an immutable version of the structure.  (Some structures would
stay uniquely-referenced their whole life - used for performance
in some single-threaded encapsulated mutation-based algorithm.)

I should also clarify one point.  I am not "asking for this language
feature" so much as "asking whether people have thought
about it".  There may (or may not) be good reasons for not offering
such a language feature.  I'm just wondering if it has been
considered.  (And trying to get a feel for the strengths and
weaknesses of Clojure - I am very new to it.)

> 3. Remember that Clojure relies on the JVM for its allocation and GC.
> Clojure is not issuing malloc and free calls. The JVM will not make it
> easy to repurpose the storage of one object with a new object, without
> going through a method.

Maybe the way to handle this (at least initially) would be to only
provide
uniqueness interfaces to some of Java's main structures.  Perhaps not
as general as would be ideal, but would easily allow repurposing via
a
method.

Thanks again for your input.

Cheers,

Mark P.

--~--~-~--~~~---~--~~
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
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: update in place for unique references

2009-01-08 Thread Mark P

> Clojure gives you a set of data structures that do very fast
> non-destructive update.  Clojure also gives you tools like atoms,
> refs, and full access to Java's mutable behavior to specify update in
> place if that's what you want.

Yes, I can see that one could implement this oneself
via Java.  But it wouldn't be an official part of the language.

What I am wondering is whether update-in-place for unique
references could lead to greater efficiencies (in some cases)
than Clojure's current non-destructive updates.  And without
harming referential transparency or concurrency benefits.

Fundamentally I would have thought update-in-place beats
update-by-replace in both execution speed and in memory
usage.  The only problem with it is that it usually breaks
referential transparency as well as causing problems
with concurrency.  But in the case of a unique reference
that is about to disappear, update-in-place does no harm!
The memory is about to become obsolete soon anyway
so why not commandeer it?  And if commandeered, why
not update it in place - as nothing else is looking at it.

I realize there are issues, but maybe these could be solved
and it could lead to even more efficient (both time and memory)
code from Clojure, while not sacrificing its strengths.

I'm just wondering whether anyone has thought about it.
And if so, whether it has potential, or whether there are
good reasons why it is not practical.

Cheers,

Mark P.

--~--~-~--~~~---~--~~
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
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
-~--~~~~--~~--~--~---



update in place for unique references

2009-01-07 Thread Mark P

I am new to clojure, but it seems very interesting.

Has anyone thought about allowing "update in place"
for situations where it is safe?

Suppose you have

  (def y (tripleit x))

and you know that there is only a single reference to x
at this point, then it would be safe to implement it as

  "y takes on the storage of x and this is multiplied
   by 3 in-place".

Well, I should say it's safe as long as "x" loses scope
at this point.  The fact that y has gained its storage and
done an update in place shouldn't bother anyone or
cause any loss in purity.

This is what "uniqueness types" are used for in the
"Clean" functional lanugage.  (And logic language
Mercury uses "unique modes".)

Now I realize there is the question in Clojure of
"how do we know whether it's unique".  Clean does it
via the type system.  But one could have other
mechanisms for ensuring uniqueness.  One would be
to keep a runtime track of references and only allow an
update-in-place primitive in the case of a single reference.
If this were attempted when multiple references existed,
a runtime error would occur.

Has anyone thought about this kind of update-in-place
methodology?  It seems to be one of the reasons why
both Clean and Mercury achieve good performance.

Perhaps there are good reasons why this approach is
not workable in clojure (or not useful), but I'd be
interested to hear why.

Thanks,

Mark.

--~--~-~--~~~---~--~~
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
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
-~--~~~~--~~--~--~---