Re: Looking for advice to fine tune a simple function

2014-02-19 Thread Mark Fisher
it's more idiomatic to use *when* rather than *if* for cases where you 
won't be considering the false path.

(when (= x y) z)

cond is used more as a multi-if with a drop out at the end (usually using 
:else which because it's a keyword is truthy when evaluated).


On Wednesday, 19 February 2014 02:25:05 UTC, Laurent Droin wrote:

 Now that I have a better understanding of what some does (i didn't 
 interpret the doc properly), it does totally make sense that it would be 
 recursive, so that's great.

 While reducing my code with Johanna's feedback, I noticed I kept using 
 cond and not if.

 Is there any meaningful difference between

 (if (= x y) z)

 and

 (cond (= x y) z)

 ?

 I see that if is a special form and cone is macro. I haven't reached the 
 chapter about macros yet in  the book I'm reading (programming Clojure). 
 Not sure if it's relevant.


-- 
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: Looking for advice to fine tune a simple function

2014-02-18 Thread Philipp Meier
Hi,

Am Sonntag, 16. Februar 2014 23:31:46 UTC+1 schrieb Laurent Droin:

 Here is a function that I came up with that takes  a bpm (heart beats per 
 minute) value, as well as a sequence of 4 values that represent the 
 boundaries defining the 5 different heart rate zones for a particular 
 person.
 The function needs to finds out in what heart zone the bpm value falls 
 into and return that zone (as a keyword - I later use that keyword in a 
 map).


I'd go with something like this:


   1. (defn r [x ps]
   2.   (some (fn [[p e]]
   3.   (when (= x p) e))
   4. (reverse ps)))
   5.  
   6. (r 7 [[0 :a] [5 :b] [10 :c]]) ;; = :b
   

-billy
 

-- 
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: Looking for advice to fine tune a simple function

2014-02-18 Thread Johanna Belanger
You can use the *pad* argument in *partition* to add x as the value of 
:zone-5, like *(partition 2 2 [x] params)*. (Note you have to supply *step* if 
you supply *pad*.) Then you don't need the *or* or the *(last params)*.

Also, like Billy did, you can use *some* instead of (*first (filter 
(complement nil?)...* The confusing thing about *some* is that it doesn't 
return the first value for which the predicate is true, it returns the 
value of the predicate the first time it is truthy. So using it to return 
the first one that isn't nil works perfectly.

And the partial function doesn't really help you here because you already 
have access to x where you need to call your function.

If you make those 3 changes, you'll have:

(defn quantize
   [x params]
 (some (fn [[b c]] (if (= x c) b)) (partition 2 2 [x] params)))




On Monday, February 17, 2014 9:04:22 PM UTC-8, Laurent Droin wrote:

 Hmmm, looks like I can replace

 #(not (nil? %))

 by
 (complement nil?)

 which seems more elegant.

 Also, it looks like I don't need that (into [] ), which will keep the code 
 cleaner.

 I think I could also get rid of the (or) by always adding (last params) 
 at the end of the sequence from which I pick the first non null element. 
 The problem with this is that I need to make sure I add this element at the 
 end of the collection, and map returns a list, which means that I would 
 need to convert it into a vector if I want to use conj.
 Or maybe there's a way to guarantee that I can add an element at the end 
 of the list.  I know it's not cheap but I'm not sure if it will make a 
 significant difference for what I'm doing. 
 I think I could really abuse the into function and that doesn't seem 
 quite right.


-- 
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: Looking for advice to fine tune a simple function

2014-02-18 Thread Laurent Droin
Wow, that's amazing. Thanks Billy and Johanna. I'm going to try all this 
tonight.

What I'm not sure of (I don't have a good understanding yet about lazy 
sequences) is whether or not the sequence given to some is lazy or not.
For example, if I have thousands of parameters but x is = the first 
boundary value (i.e. the first element in the sequence), I don't really 
want to test x against all the other boundary values in the sequence since 
I already know it's not nil.
Otherwise, I was thinking I could use recursion, take the two first 
elements of the sequence, and see if I could conclude. If not, I would call 
the function again against the rest of the 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/groups/opt_out.


Re: Looking for advice to fine tune a simple function

2014-02-18 Thread Johanna Belanger
I know. Isn't Clojure beautiful? Sigh...

In the docs for 
*partition*http://clojuredocs.org/clojure_core/clojure.core/partition, 
it says that partition returns a lazy sequence. And if you look at the 
source section of the docs for 
*some*http://clojuredocs.org/clojure_core/clojure.core/some you 
can see that it uses recursion under the hood. So you should be covered 
there.

Thanks for the interesting discussion. =)

On Tuesday, February 18, 2014 11:56:17 AM UTC-8, Laurent Droin wrote:

 Wow, that's amazing. Thanks Billy and Johanna. I'm going to try all this 
 tonight.

 What I'm not sure of (I don't have a good understanding yet about lazy 
 sequences) is whether or not the sequence given to some is lazy or not.
 For example, if I have thousands of parameters but x is = the first 
 boundary value (i.e. the first element in the sequence), I don't really 
 want to test x against all the other boundary values in the sequence since 
 I already know it's not nil.
 Otherwise, I was thinking I could use recursion, take the two first 
 elements of the sequence, and see if I could conclude. If not, I would call 
 the function again against the rest of the 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/groups/opt_out.


Re: Looking for advice to fine tune a simple function

2014-02-18 Thread Laurent Droin
He he... more research work for me tonight. Thanks Johanna for the pointers.

-- 
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: Looking for advice to fine tune a simple function

2014-02-18 Thread Laurent Droin
Now that I have a better understanding of what some does (i didn't 
interpret the doc properly), it does totally make sense that it would be 
recursive, so that's great.

While reducing my code with Johanna's feedback, I noticed I kept using 
cond and not if.

Is there any meaningful difference between

(if (= x y) z)

and

(cond (= x y) z)

?

I see that if is a special form and cone is macro. I haven't reached the 
chapter about macros yet in  the book I'm reading (programming Clojure). 
Not sure if it's relevant.

-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Andy-
On Sunday, February 16, 2014 11:19:58 PM UTC-5, Bruno Kim Medeiros Cesar 
wrote:

 (BTW, Andy, how do you format your code so prettily?)

I usually just paste it into pygments.org and then paste it back into 
google groups (which accepts the generated HTML).

Cheers 

-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Laurent Droin
Wow, thanks Gianluco, Andy and Bruno. Lots of good feedback I am trying to 
process. It's amazing how coming up with a satisfying functional 
programing style function is a complex process when you've been doing 
imperative programing all your life. It's really a whole different way of 
thinking. I like it but it will take some practice and your feedback really 
helps. It looks like I'm going to spend more time on it. I'll update.

-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Johanna Belanger
Thanks for this!

On Monday, February 17, 2014 4:49:38 AM UTC-8, Andy- wrote:

 On Sunday, February 16, 2014 11:19:58 PM UTC-5, Bruno Kim Medeiros Cesar 
 wrote:

 (BTW, Andy, how do you format your code so prettily?)

 I usually just paste it into pygments.org and then paste it back into 
 google groups (which accepts the generated HTML).

 Cheers 


-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Johanna Belanger
Hi,

I'm fairly new to clojure as well, but I like this way, and I *think* it's 
idiomatic:

Data structure:

[{:zone-max 100 :zone-key :hr-zone-1}
 {:zone-max 120 :zone-key :hr-zone-2}
 {:zone-max 140 :zone-key :hr-zone-3}
 {:zone-max 160 :zone-key :hr-zone-4}
 {:zone-max 333 :zone-key :hr-zone-5}]


And function:

(defn hr-zone
 Return the HR zone as a keyword according to the bpm value[bpm zones] 
   (:zone-key (first (filter #(= bpm (:zone-max %)) (sort-by :zone-max 
zones)

   
That's just over my parentheses-parsing comfort level, so I'd probably 
thread it for readability:

(defn hr-zone
 Return the HR zone as a keyword according to the bpm value[bpm zones] (- 
zones
 (sort-by :zone-max)
 (filter #(= bpm (:zone-max %)))
 (first)
 (:zone-key)))

 
This returns nil if given a bpm higher than the defined zones, and it 
considers negative heart rates to be in zone one, so you might want to 
handle the boundaries differently.

Happy coding,
Johanna

On Monday, February 17, 2014 6:00:40 AM UTC-8, Laurent Droin wrote:

 Wow, thanks Gianluco, Andy and Bruno. Lots of good feedback I am trying to 
 process. It's amazing how coming up with a satisfying functional 
 programing style function is a complex process when you've been doing 
 imperative programing all your life. It's really a whole different way of 
 thinking. I like it but it will take some practice and your feedback really 
 helps. It looks like I'm going to spend more time on it. I'll update.



-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Laurent Droin
All the good feedback here had me thinking a lot... Especially Andy who 
pushed me towards more abstraction.
I loved the idea of functions that return functions and researching all 
this led me to embrace partials.

Here is my current implementation of quantize. It came out of a lot of 
trial and errors (gotta love the REPL) and even though, it became more 
concise,
- I think it can be improved
- I am wondering if I'm going too far. I'm worried that it makes the 
function hard to understand for someone who would maintain it. I don't have 
enough FP experience to get an idea whether this function is well written, 
or if it's just impossible to understand. From an imperative programming 
background, it is certainly impossible to understand.

(def inf Long/MAX_VALUE)
(defn quantize
  Given a collection of ordered numeric 'markers' such as [m n],  given a 
collection of values such as [a b c],  returns a if x = m, returns b if m  x 
= n, returns c if n  x  This should work for any size collections, but the 
values neeed to have  one more element than the markers.
  [x markers values]
  (let 
[f (partial (fn([%1 %2 %3] (cond (= %1 %2) %3))) x)]
(first (filter #(not (nil? %))(map f (conj markers inf) values)


A few things I don't like:
- (conj markers inf) to artificially add an infinite enough value to my 
markers collection so that it turns [120 150 165 180] into [120 150 165 
180 infinity]. Too bad there is no infinity in Clojure.
- I hate the #(not (nil? %)) but I could not find a predicate such as 
not-nil?
- I was not able to get (some) to work in this context so I used (first 
(filter instead.
- I could probably make this more readable by applying the Clojure styling 
guide (I will)

Any idea how I could improve this function further for more elegance and 
clarity?

With this function working, I can stick it to some foundation library and 
create a simpler hr library.

My hr library would contain:

(def hr-zones [:z1 :z2 :z3 :z4 :z5])
(defn get-hr-zone [hr-zones-def bpm]
  (quantize bpm hr-zones-def hr-zones))



And then, my client application would have:

(def get-my-hr-zone 
  (partial get-hr-zone [120 150 165 180]))
(get-my-hr-zone 119)(get-my-hr-zone 120)(get-my-hr-zone 149)(get-my-hr-zone 
150)(get-my-hr-zone 151)



BTW, thanks Andy for the tip about Pygments.

-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Andy-
On Monday, February 17, 2014 6:43:18 PM UTC-5, Laurent Droin wrote:


 (def inf Long/MAX_VALUE)
 (defn quantize
   [x markers values]
   (let 
 [f (partial (fn([%1 %2 %3] (cond (= %1 %2) %3))) x)]
 (first (filter #(not (nil? %))(map f (conj markers inf) values)


The reason I didn't go with Long/MAX_VALUE is that it breaks down for 
 arbitrary precision and bigints which is a no-no for me.

There is many many ways this function could look. Mine is just one example. 
For instance many clojurist's would probably prefer to call it like this:

(quantize 0 :small 5 :med :10 :large :huge).

I didn't go through your code. But many people don't like to overuse 
anonymous functions especially if you use 3 parameters (what is %1, %2 %3?, 
if they had a name it'd be clearer). But this is just style so it's very 
subjective.

Cheers

-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Laurent Droin
All good points Andy. Thanks. I'll continue working on it until I'm happy.

I am almost never happy with anonymous functions either. In this particular 
case, though, the function is so simple that I felt it would be overkill to 
externalize it into another function (unless I'm really going to use it 
somewhere else). The fact that we don't know what the parameters are didn't 
bother me too much:

(cond (= %1 %2) %3))
I just wanted something that return the third parameter if parameter 1 = 
parameter 2. It seemed too abstract to try to label the parameters.

About the Long/MAX_VALUE, I didn't like it and you're right that it will 
only work for integers (if I read correctly, they are actually long in 
Clojure) but that won't work for all other numerical types. I don't see any 
solution to my problem besides having to do a test that is different from 
all the other tests in the function.
I also like the function signature you came up with initially. It does make 
sense and it's probably more elegant than passing two collections.

But as you said, there are many ways to implement the same thing. I would 
like to follow best practices as much as possible.

-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Laurent Droin
So here is a new attempt at the quantize function so that I no longer have 
to deal with the infinity problem:

(defn quantize-2 
  [x params]
  (let [f (partial (fn [a [b c]] (cond(= a c) b)) x)]
(or 
 (first (filter #(not (nil? %)) (map f (into [](partition 2 2 params))) 
 (last params))


params now has this form: 

[:zone-1 120 :zone-2 150 :zone-3 165 :zone-4 180 :zone-5]


i.e. the values to return are intermingled with the boundaries. I 
normally don't like mixing things but you've gotta admit that it looks just 
like how you would draw heart rates on a schema on paper: zone1 | zone 2 | 
zone 3 | zone 4 | zone 5 and you would probably have the values 120, 150, 
165 and 180 written in between the zone names, just above the | characters.

The way I got rid of the infinity is by using the or. I'm looking for the 
first non null value (when trying to find whether x is = 120, = 150, 
=165, =180, and if I don't find any, then it must be that we're in the 
last category of my params collection.

Still not sure whether it's the optimum way to do it but I'll continue 
researching (after all, this is not a professional project, I have no 
deadline, and I can keep trying to improve  - great way to learn).
The feedback I got on this post got me working and scratching my head all 
weekend. This is great. 

-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Laurent Droin
So here is a new attempt at the quantize function so that I no longer have 
to deal with the infinity problem:

(defn quantize-2 
  [x params]
  (let [f (partial (fn [a [b c]] (cond(= a c) b)) x)]
(println (first (filter #(not (nil? %))(map f (into [](partition 2 
params))
(or 
 (first (filter #(not (nil? %)) (map f (into [](partition 2 params) 
 (last params


params now has this form: 

[:zone-1 120 :zone-2 150 :zone-3 165 :zone-4 180 :zone-5]


i.e. the values to return are intermingled with the boundaries. I 
normally don't like mixing things but you've gotta admit that it looks just 
like how you would draw heart rates on a schema on paper: zone1 | zone 2 | 
zone 3 | zone 4 | zone 5 and you would probably have the values 120, 150, 
165 and 180 written in between the zone names, just above the | characters.

The way I got rid of the infinity is by using the or. I'm looking for the 
first non null value (when trying to find whether x is = 120, = 150, 
=165, =180, and if I don't find any, then it must be that we're in the 
last category of my params collection.

Still not sure whether it's the optimum way to do it but I'll continue 
researching (after all, this is not a professional project, I have no 
deadline, and I can keep trying to improve  - great way to learn).
The feedback I got on this post got me working and scratching my head all 
weekend. This is great. 

-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Laurent Droin

So here is a new attempt at the quantize function so that I no longer have 
to deal with the infinity problem:

(defn quantize-2 
  [x params]
  (let [f (partial (fn [a [b c]] (cond(= a c) b)) x)]
(or 
 (first (filter #(not (nil? %)) (map f (into [](partition 2 params) 
 (last params


params now has this form: 

[:zone-1 120 :zone-2 150 :zone-3 165 :zone-4 180 :zone-5]


i.e. the values to return are intermingled with the boundaries. I 
normally don't like mixing things but you've gotta admit that it looks just 
like how you would draw heart rates on a schema on paper: zone1 | zone 2 | 
zone 3 | zone 4 | zone 5 and you would probably have the values 120, 150, 
165 and 180 written in between the zone names, just above the | characters.

The way I got rid of the infinity is by using the or. I'm looking for the 
first non null value (when trying to find whether x is = 120, = 150, 
=165, =180, and if I don't find any, then it must be that we're in the 
last category of my params collection.

Still not sure whether it's the optimum way to do it but I'll continue 
researching (after all, this is not a professional project, I have no 
deadline, and I can keep trying to improve  - great way to learn).
The feedback I got on this post got me working and scratching my head all 
weekend. This is great. 

-- 
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: Looking for advice to fine tune a simple function

2014-02-17 Thread Laurent Droin
Hmmm, looks like I can replace

#(not (nil? %))

by
(complement nil?)

which seems more elegant.

Also, it looks like I don't need that (into [] ), which will keep the code 
cleaner.

I think I could also get rid of the (or) by always adding (last params) 
at the end of the sequence from which I pick the first non null element. 
The problem with this is that I need to make sure I add this element at the 
end of the collection, and map returns a list, which means that I would 
need to convert it into a vector if I want to use conj.
Or maybe there's a way to guarantee that I can add an element at the end of 
the list.  I know it's not cheap but I'm not sure if it will make a 
significant difference for what I'm doing. 
I think I could really abuse the into function and that doesn't seem 
quite right.

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


Looking for advice to fine tune a simple function

2014-02-16 Thread Laurent Droin
Hi,

Disclaimer - I am completely new to Clojure. I just implemented my very 
first (simple) program, letting me find out, from a GPX file, how much time 
is spent in the various heart rate zones. Now that it's working, I'm 
reviewing the code and trying to use best practices. From what I have read 
so far, there are many ways in Clojure to do the same thing and for a 
newbie, it's not always obvious to get a good grasp on what is the best way 
to  code a feature.
As a developer, and even though I love how concise Clojure programs can be, 
I am very concerned with readability and ease of maintenance so I would 
like to keep functions as short and tight as possible, but not to the point 
where it becomes hard to understand what it does.

Here is a function that I came up with that takes  a bpm (heart beats per 
minute) value, as well as a sequence of 4 values that represent the 
boundaries defining the 5 different heart rate zones for a particular 
person.
The function needs to finds out in what heart zone the bpm value falls into 
and return that zone (as a keyword - I later use that keyword in a map).

If you're an experienced Clojure developer, what would you have done 
differently (and why) ?

*(defn hr-zone*
*  Return the HR zone as a keyword according to the bpm value.*
*  [bpm [max-zone-1 max-zone-2 max-zone-3 max-zone-4]] *
*  (cond *
*(= bpm max-zone-1) :hr-zone-1*
*(and ( max-zone-1 bpm) (= max-zone-2 bpm)) :hr-zone-2 *
*(and ( max-zone-2 bpm) (= max-zone-3 bpm)) :hr-zone-3 *
*(and ( max-zone-3 bpm) (= max-zone-4 bpm)) :hr-zone-4 *
*( max-zone-4 bpm) :hr-zone-5))*

FYI, here is how I call this function in the REPL:
(def my-hr-zones-defs [120 150 165 180])

(hr-zone 115 my-hr-zones-defs)
(hr-zone 133 my-hr-zones-defs)
(hr-zone 161 my-hr-zones-defs)
(hr-zone 175 my-hr-zones-defs)
(hr-zone 192 my-hr-zones-refs)

Questions I have:
Would that make sense to consider (and maybe enforce) that the sequence 
received as parameter is sorted? If this was the case, I would assume I 
could avoid the and calls- assuming that all the conditions in the cone 
form are evaluated in order. 
Assuming that I need to test bpm against the two boundaries of each range, 
would there be a better way to do this:
*(and ( max-zone-1 bpm) (= max-zone-2 bpm))*
?
Maybe this would work, but is it preferable?
*( max-zone-1 bpm (dec **max-zone-2**))*

*Thanks in advance for the advice.*

*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
--- 
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: Looking for advice to fine tune a simple function

2014-02-16 Thread gianluca torta
to me it seems that you are anyway relying on the assumption that the 
sequence is ordered, so I think it would be convenient to drop the ands

Gianluca


On Sunday, February 16, 2014 11:31:46 PM UTC+1, Laurent Droin wrote:

 Hi,

 Disclaimer - I am completely new to Clojure. I just implemented my very 
 first (simple) program, letting me find out, from a GPX file, how much time 
 is spent in the various heart rate zones. Now that it's working, I'm 
 reviewing the code and trying to use best practices. From what I have read 
 so far, there are many ways in Clojure to do the same thing and for a 
 newbie, it's not always obvious to get a good grasp on what is the best way 
 to  code a feature.
 As a developer, and even though I love how concise Clojure programs can 
 be, I am very concerned with readability and ease of maintenance so I would 
 like to keep functions as short and tight as possible, but not to the point 
 where it becomes hard to understand what it does.

 Here is a function that I came up with that takes  a bpm (heart beats per 
 minute) value, as well as a sequence of 4 values that represent the 
 boundaries defining the 5 different heart rate zones for a particular 
 person.
 The function needs to finds out in what heart zone the bpm value falls 
 into and return that zone (as a keyword - I later use that keyword in a 
 map).

 If you're an experienced Clojure developer, what would you have done 
 differently (and why) ?

 *(defn hr-zone*
 *  Return the HR zone as a keyword according to the bpm value.*
 *  [bpm [max-zone-1 max-zone-2 max-zone-3 max-zone-4]] *
 *  (cond *
 *(= bpm max-zone-1) :hr-zone-1*
 *(and ( max-zone-1 bpm) (= max-zone-2 bpm)) :hr-zone-2 *
 *(and ( max-zone-2 bpm) (= max-zone-3 bpm)) :hr-zone-3 *
 *(and ( max-zone-3 bpm) (= max-zone-4 bpm)) :hr-zone-4 *
 *( max-zone-4 bpm) :hr-zone-5))*

 FYI, here is how I call this function in the REPL:
 (def my-hr-zones-defs [120 150 165 180])

 (hr-zone 115 my-hr-zones-defs)
 (hr-zone 133 my-hr-zones-defs)
 (hr-zone 161 my-hr-zones-defs)
 (hr-zone 175 my-hr-zones-defs)
 (hr-zone 192 my-hr-zones-refs)

 Questions I have:
 Would that make sense to consider (and maybe enforce) that the sequence 
 received as parameter is sorted? If this was the case, I would assume I 
 could avoid the and calls- assuming that all the conditions in the cone 
 form are evaluated in order. 
 Assuming that I need to test bpm against the two boundaries of each range, 
 would there be a better way to do this:
 *(and ( max-zone-1 bpm) (= max-zone-2 bpm))*
 ?
 Maybe this would work, but is it preferable?
 *( max-zone-1 bpm (dec **max-zone-2**))*

 *Thanks in advance for the advice.*

 *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
--- 
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: Looking for advice to fine tune a simple function

2014-02-16 Thread Andy-
I'm also very new to clojure but this is how I'd do it:

(def hr-zones {
   [0 100] :low
   [101 120] :fat-burn
   [121 140] :aerobic
   [141 160] :anaerobic
   [161 333] :max})

(defn hr-zone [hr]
  (some (fn [x]
(and (= (first (key x)) hr (second (key x)))
 (val x)))
hr-zones))


This method does have some disadvantages however (you have to make sure the 
boundaries are correct and it doesn't handle floating points like 140.4).

Whenever you see yourself repeating code (like the 3-4 if's you have) then 
you have to take a step back and maybe change your data structure so that 
your algorithm is easier.

Mathematically speaking you're really quantizing your data (aka applying a 
piecewise constant function). So you could even take another step back and 
make it more general. So find a data structure that represents the function 
(ie the intervals and the function value for each interval) and then you 
could come up with a function like quantize or mk-piecewise-const-fn 
that returns a function. So you could then do:

(let [myfn (mk-piecewise-const-fn [[100 :zone-1] [120 :zone-2] ...] ]
   myzone (myfn 142)]

and you have a general function  which you can now use with a much wider 
range of problems (not just specific to your hr-zone conversion).

But I'm too lazy to come up with a implementation for mk-piecewise-const-fn 
:)

HTH


On Sunday, February 16, 2014 5:31:46 PM UTC-5, Laurent Droin wrote:

 Hi,

 Disclaimer - I am completely new to Clojure. I just implemented my very 
 first (simple) program, letting me find out, from a GPX file, how much time 
 is spent in the various heart rate zones. Now that it's working, I'm 
 reviewing the code and trying to use best practices. From what I have read 
 so far, there are many ways in Clojure to do the same thing and for a 
 newbie, it's not always obvious to get a good grasp on what is the best way 
 to  code a feature.
 As a developer, and even though I love how concise Clojure programs can 
 be, I am very concerned with readability and ease of maintenance so I would 
 like to keep functions as short and tight as possible, but not to the point 
 where it becomes hard to understand what it does.

 Here is a function that I came up with that takes  a bpm (heart beats per 
 minute) value, as well as a sequence of 4 values that represent the 
 boundaries defining the 5 different heart rate zones for a particular 
 person.
 The function needs to finds out in what heart zone the bpm value falls 
 into and return that zone (as a keyword - I later use that keyword in a 
 map).

 If you're an experienced Clojure developer, what would you have done 
 differently (and why) ?

 *(defn hr-zone*
 *  Return the HR zone as a keyword according to the bpm value.*
 *  [bpm [max-zone-1 max-zone-2 max-zone-3 max-zone-4]] *
 *  (cond *
 *(= bpm max-zone-1) :hr-zone-1*
 *(and ( max-zone-1 bpm) (= max-zone-2 bpm)) :hr-zone-2 *
 *(and ( max-zone-2 bpm) (= max-zone-3 bpm)) :hr-zone-3 *
 *(and ( max-zone-3 bpm) (= max-zone-4 bpm)) :hr-zone-4 *
 *( max-zone-4 bpm) :hr-zone-5))*

 FYI, here is how I call this function in the REPL:
 (def my-hr-zones-defs [120 150 165 180])

 (hr-zone 115 my-hr-zones-defs)
 (hr-zone 133 my-hr-zones-defs)
 (hr-zone 161 my-hr-zones-defs)
 (hr-zone 175 my-hr-zones-defs)
 (hr-zone 192 my-hr-zones-refs)

 Questions I have:
 Would that make sense to consider (and maybe enforce) that the sequence 
 received as parameter is sorted? If this was the case, I would assume I 
 could avoid the and calls- assuming that all the conditions in the cone 
 form are evaluated in order. 
 Assuming that I need to test bpm against the two boundaries of each range, 
 would there be a better way to do this:
 *(and ( max-zone-1 bpm) (= max-zone-2 bpm))*
 ?
 Maybe this would work, but is it preferable?
 *( max-zone-1 bpm (dec **max-zone-2**))*

 *Thanks in advance for the advice.*

 *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
--- 
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: Looking for advice to fine tune a simple function

2014-02-16 Thread Andy-
I realized I could use that at some of my code so I wrote it. Not sure if 
it's the best possible implementation but here it is:

(defn quantizer
  Returns a function that quantizes input data which when called with 'x' 
returns:   o 1st val if-Inf  x = 1st bound   o 2st val if 1st 
bound  x = 2st bound   o ...   o last val if last-1 bound  x = last 
bound   o max if x  last bound where m is a vector of vectors where 
the first element specifies the boundary and   the second element the value 
which to return. Example:   (def points-grade (quantizer [[40 :F] [60 :D] 
[80 :C] [90 :B]] :A))   (map points-grade [10 80 93])   ; (:F :C :A)
  [m max]
  (fn [x]
(if (= x (first (first m)))
  (second (first m))
  (if ( x (first (last m)))
max
(some 
 (fn [i] 
   (let [[[l lv] [h hv]] i]
 (and ( l x) (= x h) hv)))
 (partition 2 1 m))


Cheers


On Sunday, February 16, 2014 6:47:51 PM UTC-5, Andy- wrote:

 I'm also very new to clojure but this is how I'd do it:

 (def hr-zones {
[0 100] :low
[101 120] :fat-burn
[121 140] :aerobic
[141 160] :anaerobic
[161 333] :max})

 (defn hr-zone [hr]
   (some (fn [x]
 (and (= (first (key x)) hr (second (key x)))
  (val x)))
 hr-zones))


 This method does have some disadvantages however (you have to make sure 
 the boundaries are correct and it doesn't handle floating points like 
 140.4).

 Whenever you see yourself repeating code (like the 3-4 if's you have) then 
 you have to take a step back and maybe change your data structure so that 
 your algorithm is easier.

 Mathematically speaking you're really quantizing your data (aka applying a 
 piecewise constant function). So you could even take another step back and 
 make it more general. So find a data structure that represents the function 
 (ie the intervals and the function value for each interval) and then you 
 could come up with a function like quantize or mk-piecewise-const-fn 
 that returns a function. So you could then do:

 (let [myfn (mk-piecewise-const-fn [[100 :zone-1] [120 :zone-2] ...] ]
myzone (myfn 142)]

 and you have a general function  which you can now use with a much wider 
 range of problems (not just specific to your hr-zone conversion).

 But I'm too lazy to come up with a implementation for 
 mk-piecewise-const-fn :)

 HTH


 On Sunday, February 16, 2014 5:31:46 PM UTC-5, Laurent Droin wrote:

 Hi,

 Disclaimer - I am completely new to Clojure. I just implemented my very 
 first (simple) program, letting me find out, from a GPX file, how much time 
 is spent in the various heart rate zones. Now that it's working, I'm 
 reviewing the code and trying to use best practices. From what I have read 
 so far, there are many ways in Clojure to do the same thing and for a 
 newbie, it's not always obvious to get a good grasp on what is the best way 
 to  code a feature.
 As a developer, and even though I love how concise Clojure programs can 
 be, I am very concerned with readability and ease of maintenance so I would 
 like to keep functions as short and tight as possible, but not to the point 
 where it becomes hard to understand what it does.

 Here is a function that I came up with that takes  a bpm (heart beats per 
 minute) value, as well as a sequence of 4 values that represent the 
 boundaries defining the 5 different heart rate zones for a particular 
 person.
 The function needs to finds out in what heart zone the bpm value falls 
 into and return that zone (as a keyword - I later use that keyword in a 
 map).

 If you're an experienced Clojure developer, what would you have done 
 differently (and why) ?

 *(defn hr-zone*
 *  Return the HR zone as a keyword according to the bpm value.*
 *  [bpm [max-zone-1 max-zone-2 max-zone-3 max-zone-4]] *
 *  (cond *
 *(= bpm max-zone-1) :hr-zone-1*
 *(and ( max-zone-1 bpm) (= max-zone-2 bpm)) :hr-zone-2 *
 *(and ( max-zone-2 bpm) (= max-zone-3 bpm)) :hr-zone-3 *
 *(and ( max-zone-3 bpm) (= max-zone-4 bpm)) :hr-zone-4 *
 *( max-zone-4 bpm) :hr-zone-5))*

 FYI, here is how I call this function in the REPL:
 (def my-hr-zones-defs [120 150 165 180])

 (hr-zone 115 my-hr-zones-defs)
 (hr-zone 133 my-hr-zones-defs)
 (hr-zone 161 my-hr-zones-defs)
 (hr-zone 175 my-hr-zones-defs)
 (hr-zone 192 my-hr-zones-refs)

 Questions I have:
 Would that make sense to consider (and maybe enforce) that the sequence 
 received as parameter is sorted? If this was the case, I would assume I 
 could avoid the and calls- assuming that all the conditions in the cone 
 form are evaluated in order. 
 Assuming that I need to test bpm against the two boundaries of each 
 range, would there be a better way to do this:
 *(and ( max-zone-1 bpm) (= max-zone-2 bpm))*
 ?
 Maybe this would work, but is it preferable?
 *( max-zone-1 bpm (dec **max-zone-2**))*

 *Thanks in advance for the advice.*

 *Laurent. *



-- 
You received this message because 

Re: Looking for advice to fine tune a simple function

2014-02-16 Thread Bruno Kim Medeiros Cesar
I can't claim to be an experienced Clojure developer, specially so 
regarding maintainability as I'm the only reader of what I write. Andy 
provided a great piece of code, although I scratched my head for a second 
or two unwrapping the last two lines. You'll be surprised how often 
(partition * 1) comes up, as it provides a sliding window through a 
sequence.

(BTW, Andy, how do you format your code so prettily?)

Regarding your question about expecting a sorted input: why don't you 
ensure it? These are the (very similar) options to enforce a precondition 
that I know of:










*(defn hr-zone [bpm [zone-1 zone-2 zone-3 zone-4 :as zones]]  {:pre [( 
zone-1 zone-2 zone-3 zone-4)]} ...) ; I don't see this very often, but it's 
simple(defn hr-zone [bpm [zone-1 zone-2 zone-3 zone-4 :as zones]]  (assert 
( zone-1 zone-2 zone-3 zone-4)} Not sorted!) ...) ; throws an error just 
as the above one, but with a provided message(defn hr-zone [bpm [zone-1 
zone-2 zone-3 zone-4 :as zones]]  (when-not ( zone-1 zone-2 zone-3 
zone-4)} (throw (Exception. Not sorted!))) ...) ; If you want to be able 
to catch the error, you may throw an exception*sorted? does not do what you 
may expect: it tests whether the data structure implements Sorted, such as 
sorted-set and sorted-map. You may get the same behaviour with (apply = 
coll) or (apply  coll) for numeric collections.

For me, the simplest option is




*(defn hr-zone [bpm zones]  (let [[zone-1 zone-2 zone-3 zone-4] (sort 
zones)]...)*
which never fails, although may not be what you need (for example, you'd 
like to be alerted if you input [174 178 128 186] when you wanted [174 178 
182 186]).

Hope that helps a bit,

Bruno Kim.

On Sunday, February 16, 2014 7:31:46 PM UTC-3, Laurent Droin wrote:

 Hi,

 Disclaimer - I am completely new to Clojure. I just implemented my very 
 first (simple) program, letting me find out, from a GPX file, how much time 
 is spent in the various heart rate zones. Now that it's working, I'm 
 reviewing the code and trying to use best practices. From what I have read 
 so far, there are many ways in Clojure to do the same thing and for a 
 newbie, it's not always obvious to get a good grasp on what is the best way 
 to  code a feature.
 As a developer, and even though I love how concise Clojure programs can 
 be, I am very concerned with readability and ease of maintenance so I would 
 like to keep functions as short and tight as possible, but not to the point 
 where it becomes hard to understand what it does.

 Here is a function that I came up with that takes  a bpm (heart beats per 
 minute) value, as well as a sequence of 4 values that represent the 
 boundaries defining the 5 different heart rate zones for a particular 
 person.
 The function needs to finds out in what heart zone the bpm value falls 
 into and return that zone (as a keyword - I later use that keyword in a 
 map).

 If you're an experienced Clojure developer, what would you have done 
 differently (and why) ?

 *(defn hr-zone*
 *  Return the HR zone as a keyword according to the bpm value.*
 *  [bpm [max-zone-1 max-zone-2 max-zone-3 max-zone-4]] *
 *  (cond *
 *(= bpm max-zone-1) :hr-zone-1*
 *(and ( max-zone-1 bpm) (= max-zone-2 bpm)) :hr-zone-2 *
 *(and ( max-zone-2 bpm) (= max-zone-3 bpm)) :hr-zone-3 *
 *(and ( max-zone-3 bpm) (= max-zone-4 bpm)) :hr-zone-4 *
 *( max-zone-4 bpm) :hr-zone-5))*

 FYI, here is how I call this function in the REPL:
 (def my-hr-zones-defs [120 150 165 180])

 (hr-zone 115 my-hr-zones-defs)
 (hr-zone 133 my-hr-zones-defs)
 (hr-zone 161 my-hr-zones-defs)
 (hr-zone 175 my-hr-zones-defs)
 (hr-zone 192 my-hr-zones-refs)

 Questions I have:
 Would that make sense to consider (and maybe enforce) that the sequence 
 received as parameter is sorted? If this was the case, I would assume I 
 could avoid the and calls- assuming that all the conditions in the cone 
 form are evaluated in order. 
 Assuming that I need to test bpm against the two boundaries of each range, 
 would there be a better way to do this:
 *(and ( max-zone-1 bpm) (= max-zone-2 bpm))*
 ?
 Maybe this would work, but is it preferable?
 *( max-zone-1 bpm (dec **max-zone-2**))*

 *Thanks in advance for the advice.*

 *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
--- 
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.