Re: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread Thomas Heller
FWIW before I came to Clojure I did a lot of Erlang and in the beginning I 
was at the exact same spot wanting to use pattern matching everywhere 
because it is so damn cool. Same goes for tagged literals.

After a little while I realized that it is just not the way to do it in 
Clojure and forcing the Erlang(or Elixir)-Way onto Clojure is not ideal and 
probably overthinking it. Protocols provide a good/better solution to some 
problems and using Clojure's excellent handling&support of "data" solves 
the rest. While it might feel weird in the beginning, wait a while for 
Clojure to click and you probably won't even miss pattern matching.

Looking at the "(defn register [...])" example. Where is the problem with 
the first solution? It doesn't have the bugs the other implementations have 
and is extremely simple to reason about? The other two solutions do the 
exact same thing just slower with absolutely no gain. If you need the 
"status" abstraction use a real state machine. Don't write a recursive 
function when you don't have to. The code should never be at a point where 
it can be called with forged data and directly skip over the :create and 
:check-unqiue states which is possible in 2 of the 3 solutions.

Embrace the data and data all the things is all I have to say.

Also if you like types (using prismatic/schema [1], core.typed looks pretty 
similar):

(def ContactId s/Int)

(s/defrecord Placeholder
[text :- s/Str])

(s/defrecord Existing
[contact-id :- ContactId])

(s/defrecord OneOff
[name :- s/Str
 email :- s/Str])

(def Recipient
  (s/either PlaceHolder
Existing
OneOff))

Just my 2 cents,
/thomas

[1] https://github.com/Prismatic/schema


>  
> Possible F# (might not compipe!!)
>
> Recipient = | Placeholder of string
>| Existing of ContactId
>| OneoffRecipient of string * string
>
>
> Possible options in Clojure
>
> {:type :placeholder ; or :existing :one-off
>  :placeholder-text :all-my-team-mates
>  :name nil
>  :email nil
>  :contact-id nil
> }
>
> ;; or
>
> (defrecord PlaceholdRecipient [placeholder-text])
> (defrecord ExistingReceipient [contact-id])
> (defrecord OneoffReceipient [name email])
>
> ;; or 
>
> [:one-off name email]
> [:existing contact-id]
> [:placeholder text]
> ;; [:self]
>
> The variant needed not be a two element vector. It is a 1 or more element 
> vector. We could just as easily have a fourth variant [:self] with no data 
> to indicate send message to self. 
>
> To actually use the above data structures and get the actual email 
> addresses from them, we need atleast three methods - 1) fetch the emails of 
> all the users team mates, 2) fetch the email for a contact in the 
> datastore, 3) return the email as is. We could implement these using a 
> multi method or implement some protocol or use a pattern matched method. 
> Each choice has a different extensibility story and are all equally valid. 
> We don't always replace every hashmap with a record. Variants are a viable 
> alternative over using a map like the one shown in the first Clojure 
> choice. 
>
> >> As much as possible I try to build my apps in such a way that the 
> program can self-explore the data you give it to self-optimize, 
> self-extend, or otherwise provide flexibility to the programmer. You can't 
> do that with a variant as a vector. Hand a vector to a function and the 
> logic has to be something like "If this is a two element vector and the 
> first thing is a keyword, then this might be a variant, but I'm not sure 
> because it could also just be a vector". While if you pass in a record, 
> type, or even a variant type, it's trivial to have a program recognize that 
> value and act upon it. 
>
> I have no experience writing apps that had to operate on any arbitrary 
> data with any arbitrary structure. Pretty much all the functions in my apps 
> could rely on data arriving in a particular format in a particular order 
> (positional destructuring). 
>
> More importantly we are pretty much agreeing that [:tagged vectors with 
> some data] are only a representation of a variant. One chosen out of 
> convenience and existing feature set. We could have a defrecord Variant 
> with two fields, a type keyword and value hashmap. If core.match was able 
> to easily pattern match over a record as well as easily destructure the 
> values in the value hashmap, we would use it. From what I have seen of 
> core.match, it is nowhere near as easy/clean as pattern matching a vector.
>
> >> As far as performance goes, this is normally the sort of thing that 
> gets baked into an app at a pretty low level, that's why I suggest it 
> should be as fast as possible. If you're going to be processing millions of 
> these things during the life of an app, and transforming them from one 
> format to another, a little tweaking here and there may save you some pain 
> in the end. 
>
> Pattern matching itself is too slow for it to be viable in

usage of "and"

2015-09-07 Thread jongwon.choi
Typo?

  (and cnt (pos? cnt))

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


usage of "and"

2015-09-07 Thread Alex Miller
Looks like a typo - these things happen. :)

If you file it here we will get updated in the ebook (not sure yet how often 
that will update):

https://pragprog.com/titles/vmclojeco/errata

-- 
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: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread James Reeves
On 6 September 2015 at 15:38, Timothy Baldridge 
wrote:

> >> I'm not sure why you think that it "complicates the code, and makes it
> harder to understand".
>
> Alright, I'll use the phrase: using vectors as variants complects order
> with data. If you hand me a vector that says [:name "tim"] I have to know
> that "the first thing in this vector is the name of the thing, the second
> thing is the value of the thing". In addition, I have to know that you
> passed me a variant. But if you simply passed me either #my.app.Name["tim"]
> or #my.app.Variant{:key :name :value "tim"} I can programmatically
> deconstruct that value into something usable by my system.
>

How? What can your program reasonably infer from that? If you remove the
semantic information from your examples (which is only meaningful to
humans), you get:

#xxx.yyy["zzz"]
#xxx.yyy{:aaa :www, :bbb "zzz"}

What does that allow us to programmatically infer? That the type is
"xxx.yyy" and that it may contain strings and keywords, but that's about
it. What good is that?

If the type satisfies known protocols, then you have more information, but
if you don't use polymorphism the only benefit is that you know the type,
which is almost meaningless by itself.

In fact, one could argue that it hampers programmatic analysis if you're
using maps. For instance, if you have a variant to set an expiry date:

[:cache/expires #inst "2016-01-01T00:00:00.000Z"]

Then you can fold this into a map:

{:cache/resource #url "http://example.com/foo";
 :cache/expires #inst "2016-01-01T00:00:00.000Z"}

If you use a custom type instead of a variant:

#cache/Expires [#inst "2016-01-01T00:00:00.000Z"]

Then the software can no longer infer that this is related to the key on
the map.

I also disagree that variants "complect order with data". By that logic, a
coordinate of:

[4 3]

Should be better expressed as:

#coord2d {:x 4, :y 3}

And a function like:

(swap! a inc)

Should be expressed as:

(swap! :atom a, :function inc)

Keywords have their place, but I don't think using positional indexes to
look up data is necessarily bad, assuming that the vector or list is very
small.

It's worth noting that Datomic uses vectors to represent transactions,
rather than maps or records, so presumably Rich and the other folks at
Cognitect are not above using positional indexing in certain cases.


> As far as performance goes, this is normally the sort of thing that gets
> baked into an app at a pretty low level, that's why I suggest it should be
> as fast as possible. If you're going to be processing millions of these
> things during the life of an app, and transforming them from one format to
> another, a little tweaking here and there may save you some pain in the
> end.
>

I was curious as to whether records really were faster than a vector
lookup. It turns out that vectors are faster:

=> (defrecord Foo [x y])
user.Foo

=> (let [f (->Foo 1 2)] (quick-bench (:x f)))
Execution time mean : 6.592069 ns

=> (let [f [1 2]] (quick-bench (f 0)))
Execution time mean : 4.758705 ns

=> (let [f [1 2]] (quick-bench (let [[x y] f] (+ x y
Execution time mean : 19.388727 ns

=> (let [f (->Foo 1 2)] (quick-bench (let [{:keys [x y]} f] (+ x y
Execution time mean : 68.845332 ns

That said, a core.match is still going to be slower than a protocol lookup,
so depending on your use-case using a record might still be quicker, but in
terms of actually pulling information out, vectors are quicker.

- James

-- 
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: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread James Reeves
On 6 September 2015 at 09:57, Amith George  wrote:
>
> Could you elaborate on what you mean by variants being like a key value
> pair?
>

I mean that tags are usually used to describe what the data *is*, whereas
keys are usually used to describe what the data is for. For instance, one
might have a map like:

{:created-date #inst "2015-09-07T12:30:00.000Z"
 :modified-date #inst "2015-09-07T13:00:00.000Z"}

The tags describe what the values are: instances in time. The keys describe
what the data is for: to record when the entity was created and modified.

In the same way, I'd consider variants another way of connecting a data
value with an indicator of its purpose.

- James

-- 
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: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread James Reeves
On 7 September 2015 at 13:59, James Reeves  wrote:

> On 6 September 2015 at 15:38, Timothy Baldridge 
> wrote:
>>
>> As far as performance goes, this is normally the sort of thing that gets
>> baked into an app at a pretty low level, that's why I suggest it should be
>> as fast as possible. If you're going to be processing millions of these
>> things during the life of an app, and transforming them from one format to
>> another, a little tweaking here and there may save you some pain in the
>> end.
>>
>
> I was curious as to whether records really were faster than a vector
> lookup. It turns out that vectors are faster:
>

I realised after I sent my email that you were earlier referring to
creation rather than lookup. In such a case, it *is* slightly quicker to
use a record:

=> (let [x 1 y 2] (quick-bench (->Foo x y)))
Execution time mean : 9.578002 ns
=> (let [x 1 y 2] (quick-bench [x y]))
Execution time mean : 12.213409 ns

So in terms of performance, it matters whether you're primarily reading or
primarily writing. Vectors are faster for lookups, records are faster for
creation. That said, if performance is important enough that even a couple
of nanoseconds per iteration matter, then perhaps an array should be used
instead.

- James

-- 
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: Uberjar woes

2015-09-07 Thread Fenton Travers
I've had this problem too.  I solved in a slightly different way.  I had my 
main function in a clojure file that also defined a component.  I moved my 
main function into a different file and that did the trick.  I didn't need 
a :gen-class directive in each file that had a component.  I didn't need to 
bring my user.clj into my main source tree, I didn't need the 
:clean-non-project-files false directive either...just pulled the main 
function out of the file that also defined a component.  

Each time I did a 

 lein clean; lein deps; lein compile; lein repl


  -or- 
 
lein clean; lein deps; lein compile; lein uberjar



These are the directives I did use in my project.clj:

 
 :main example.core
  :uberjar {:aot :all}
  :aot [example.core]
  :repl-options {:init-ns user}



-- 
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: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread Amith George

>
> Looking at the "(defn register [...])" example. Where is the problem with 
> the first solution? It doesn't have the bugs the other implementations have 
> and is extremely simple to reason about? The other two solutions do the 
> exact same thing just slower with absolutely no gain. If you need the 
> "status" abstraction use a real state machine. Don't write a recursive 
> function when you don't have to. The code should never be at a point where 
> it can be called with forged data and directly skip over the :create and 
> :check-unqiue states which is possible in 2 of the 3 solutions.
>

It bothered me as well that register could skip states. I couldn't figure 
out how to deal with that and resorted to making the function private :( . 
I was originally thinking - the sum of the all steps being the 
variant/sum-type and each step being one of the cases of the variant. 
However as you said, a state machine might be a better representation. 
Maybe this was a bad use case for variants. The output of the state machine 
steps could be a variant over :ok, :err. Either way lets ignore this usage. 


(def Recipient
>   (s/either PlaceHolder
> Existing
> OneOff))
>

This looks interesting. Where would I actually use this? I mean, if I have 
created three records, I may as well implement multi methods or protocols, 
right? Even if I don't do those, I will still need to use `(condp instance? 
obj ...)` or equivalent to select the appropriate branch for processing. Is 
there a way I can use Recipient to select a branch? 

I am not proposing the variant vector to be used in place of records. I am 
looking at it as an improvement over using a hashmap containing a :type 
key. For some reason I am wary of records. The variant vector seemed like a 
good intermediate solution. 

On Monday, 7 September 2015 17:13:53 UTC+5:30, Thomas Heller wrote:
>
>
>
>>

-- 
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: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread Timothy Baldridge
>> Should be expressed as:
>> (swap! :atom a, :function inc)

One of Rich's talks on simplicity actually addresses that. He states that
the above method (with keyword arguments) is actually simpler, but that
this isn't exactly easy to program.

And yes, I would take this same position about positional vectors being a
type instead of a list or persistent vector. Same thing with Ratios we
could represent them as [numerator denominator] but we don't as its simpler
to give them their own type, and then I can easily determine if a [11 22]
is a ratio, a 2D point or even a variant.

Types are good even in dynamic languages, we should use the more. As
mentioned by Thomas, records are the idiomatic way to store typed
information in Clojure. They're simple, elegant, and interop very cleanly
with the rest of the system. So that's why I react when someone takes a
conference talk as an example of "the way it should be done". The above
video is a exploratory explanation of a different way of thinking of data,
but I have never seen code like that in production, and it's so different
from idiomatic Clojure, that I would be hesitant to adopt it wholesale.

Timothy

-- 
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: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread Thomas Heller

>
>
> (def Recipient
>>   (s/either PlaceHolder
>> Existing
>> OneOff))
>>
>
> This looks interesting. Where would I actually use this? I mean, if I have 
> created three records, I may as well implement multi methods or protocols, 
> right? Even if I don't do those, I will still need to use `(condp instance? 
> obj ...)` or equivalent to select the appropriate branch for processing. Is 
> there a way I can use Recipient to select a branch? 
>

I probably wouldn't use protocols since I doubt there is a function 
signature that is exactly identical for all branches. Each branch probably 
needs access to different parts of your system (eg. database) and always 
passing everything to everything is not ideal.

Multi-Method is great if you want something openly extensible but that 
again seems unlikely here and also assumes that everything requires the 
same arguments.

cond(p) sounds perfect for this case. I tend to write each branch as a 
single function and keep the dispatch as compact as possible.

(defn send-placeholder [thing {:keys [text]}]
  ...)

(defn send-existing [db thing {:keys [contact-id]}]
  ...)

(defn send-one-off [something thing {:keys [name email]}]
  ...)

(defn send [app thing recipient]
  (condp instance? recipient
PlaceHolder
(send-placeholder thing recipient)
Existing
(send-existing (:db app) thing recipient)
OneOff
(send-one-off (:something app) thing recipient)))


That greatly reduces the cognitive load when looking at each separate 
implementation and also keeps the actual internal structure of the 
Recipient out of the dispatch. The conpd does not need to know how many 
fields are in OneOff, the tuple/vector/variant match versions must know 
that. 

/thomas






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


add concurrency feature as language spec.

2015-09-07 Thread Renjith Thankachan
I have seen clojure now has different platform implementation.It would be 
good if its concurrency spec. must be a language style spec. like "go" ing 
Golang.
Clojure-CLR,Clojure-Java,Clojurescript need a common concurrency spec.

-- 
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: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread James Reeves
On 7 September 2015 at 15:49, Timothy Baldridge 
wrote:
>
> Types are good even in dynamic languages, we should use the more. As
> mentioned by Thomas, records are the idiomatic way to store typed
> information in Clojure.
>

I don't think that's true. Or rather, I think it depends on what you mean
by "type".

In core.typed parlance, a "type" is a means of validating the shape of data
at compile time. We can use a vector to represent a variant, and still have
it typed:

(defalias FooResult
  (U '[(Value :ok) Int]
 '[(Value :err) Str]))

Dynamic typing libraries like Schema or Annotate have a similar notion of
types, but perform their checks at runtime. In both cases, the type is
independent of the data; we can determine whether a data structure matches
a specific type, but the type isn't tied to the data.

In contrast, we have a notion of what core.typed and edn calls a "tag",
which is attached directly to the data structure. A record is essentially a
tagged map, and if we didn't have to worry about performance, tags would
probably just be implemented as metadata.

If we're talking about records, then we're talking about tags more than
types, and the question becomes: what data should we tag?

If we want runtime polymorphism, then it makes sense to use a tag so we
have something to dispatch off. But is there any other practical reason
we'd want to use a tagged structure in Clojure?

I'm not convinced there is. Records are useful for polymorphism, and
perhaps performance if that level of optimisation is necessary, but I don't
see any other benefit.


> The above video is a exploratory explanation of a different way of
> thinking of data, but I have never seen code like that in production, and
> it's so different from idiomatic Clojure, that I would be hesitant to adopt
> it wholesale.
>

A lot of people use Instaparse and Hiccup in production, which I believe
the video explicitly mentions as being examples of variants.

- James

-- 
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: add concurrency feature as language spec.

2015-09-07 Thread James Reeves
You mean like core.async?

- James

On 7 September 2015 at 16:49, Renjith Thankachan 
wrote:

> I have seen clojure now has different platform implementation.It would be
> good if its concurrency spec. must be a language style spec. like "go" ing
> Golang.
> Clojure-CLR,Clojure-Java,Clojurescript need a common concurrency spec.
>
> --
> 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.
>

-- 
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: usage of "and"

2015-09-07 Thread Lee Spector

> On Sep 7, 2015, at 7:58 AM, jongwon.choi  wrote:
> 
> Typo?
> 
>  (and cnt (pos? cnt))

Sometimes this kind of thing is reasonable if cnt might be nil, which would 
break pos?. 

So the expression says "cnt isn't nil (or false) and it's positive."

 -Lee

-- 
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: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread Amith George
>> I probably wouldn't use protocols since I doubt there is a function 
signature that is exactly identical for all branches. Each branch probably 
needs access to different parts of your system (eg. database) and always 
passing everything to everything is not ideal.

>> Multi-Method is great if you want something openly extensible but that 
again seems unlikely here and also assumes that everything requires the 
same arguments.

I had the same concerns and wanted to use a simple function with 
pattern/condition matching to dispatch to the appropriate function. I had 
considered using Records as synonymous with using polymorphic calls (multi 
methods, protocols). Its good to know the alarm bells ringing in my head 
had merit :). Thanks for that.  

Thinking out loud, if we are not using Records for polymorphism, are we 
using it to guarantee structure? If you could indulge me a little more, 
consider the following two implementations. 


(def OneOff [(s/one s/Str 'name) (s/one s/Str 'email)])

(defn send-one-off
  [something thing [name email :as data]]
  {:pre [(s/validate OneOff data)]}
  ,,,)

(defn send 
  [app thing recipient]
  (match [recipient]
[[:one-off & data]] (send-one-off (:something app) thing data)))




Individual schema are created for each variant case and are checked against 
by the respective functions. The dispatch function only needs to know how 
to check for individual cases of the variant. 


(def OneOffMap {:type (s/eq :one-off) :name s/Str :email s/Str})
(def ExistingContactMap {:type (s/eq :existing) :contact-id s/Int})

(def Recipient (s/either ExistingContactMap OneOffMap))
;; s/either is deprecated and s/cond-pre is recommended
;; however, validating valid OneOffMap data using the following 
;; still throws an error.
;; (def Recipient (s/cond-pre ExistingContactMap OneOffMap))

(defn send-one-off
  [something thing {:keys [name email] :as data}]
  ,,,)

(defn send 
  [app thing recipient]
  {:pre [(s/validate Recipient recipient)]}
  (match [(:type recipient)]
[:one-off] (send-one-off (:something app) thing recipient)))

This reverts to using a map with a :type key. Individuals schema for each 
:type value. A combined schema to represent a recipient. The dispatch 
function only needs to know about the existence of the :type key and the 
values it can handle.


Whether we use records or maps or variants, the dispatch function needs to 
know what contract is implemented by recipient. Whether it will be an 
instance of something, or a variant or a map with type keys. Neither 
versions care for any other data present in recipient or its structure.

At this point I am confused, what makes one version better than the other. 
Creating schema definitions for the records seemed a lot easier than for 
the other two. Also I am assuming that if records are created using 
s/defrecord, the factory functions (->, map->) will automatically validate 
them?

I really appreciate you taking the time to clarify things for me.

--
Amith


On Monday, 7 September 2015 20:57:46 UTC+5:30, Thomas Heller wrote:
>
>
>> (def Recipient
>>>   (s/either PlaceHolder
>>> Existing
>>> OneOff))
>>>
>>
>> This looks interesting. Where would I actually use this? I mean, if I 
>> have created three records, I may as well implement multi methods or 
>> protocols, right? Even if I don't do those, I will still need to use 
>> `(condp instance? obj ...)` or equivalent to select the appropriate branch 
>> for processing. Is there a way I can use Recipient to select a branch? 
>>
>
> I probably wouldn't use protocols since I doubt there is a function 
> signature that is exactly identical for all branches. Each branch probably 
> needs access to different parts of your system (eg. database) and always 
> passing everything to everything is not ideal.
>
> Multi-Method is great if you want something openly extensible but that 
> again seems unlikely here and also assumes that everything requires the 
> same arguments.
>
> cond(p) sounds perfect for this case. I tend to write each branch as a 
> single function and keep the dispatch as compact as possible.
>
> (defn send-placeholder [thing {:keys [text]}]
>   ...)
>
> (defn send-existing [db thing {:keys [contact-id]}]
>   ...)
>
> (defn send-one-off [something thing {:keys [name email]}]
>   ...)
>
> (defn send [app thing recipient]
>   (condp instance? recipient
> PlaceHolder
> (send-placeholder thing recipient)
> Existing
> (send-existing (:db app) thing recipient)
> OneOff
> (send-one-off (:something app) thing recipient)))
>
>
> That greatly reduces the cognitive load when looking at each separate 
> implementation and also keeps the actual internal structure of the 
> Recipient out of the dispatch. The conpd does not need to know how many 
> fields are in OneOff, the tuple/vector/variant match versions must know 
> that. 
>
> /thomas
>
>
>
>
>
>
>

-- 
You received this message because you are subscribed to the 

Re: Just found out about Elixirs function argument pattern matching...

2015-09-07 Thread dennis zhuang
Thanks for your benchmark.
I will upgrade all the dependencies and release 0.2.0

We are using defun with instparse in a DSL implementation, the performance
is acceptable, but the code is much more readable.





2015-09-06 4:33 GMT+08:00 Rob Lally :

> Out of interest, I ran the benchmarks as is, and got more or less the same
> results - 15x. Then I tried upgrading the defun dependencies - clojure,
> core.match and tools.macro - all of which have newer versions, and then
> running the benchmarks without leiningen’s jvm-opts and in a trampolined
> repl. The results are better (see below). Still not great - but down from
> 15x to 10x.
>
> That said:
>
> * I’m not sure I’d care: for most applications the overhead of function
> dispatch is probably not the bottleneck.
> * Elixir and the BEAM VM are awesome at many things, but I suspect (from
> experience not evidence) that the defun version is still faster than the
> elixir version.
>
>
> Rob
>
> ---
>
> user=> (bench (accum-defn 1))
> WARNING: Final GC required 2.590098761776679 % of runtime
> Evaluation count : 429360 in 60 samples of 7156 calls.
>  Execution time mean : 139.664539 µs
> Execution time std-deviation : 4.701755 µs
>Execution time lower quantile : 134.451108 µs ( 2.5%)
>Execution time upper quantile : 150.214646 µs (97.5%)
>Overhead used : 1.565276 ns
>
> Found 5 outliers in 60 samples (8. %)
> low-severe   5 (8. %)
>  Variance from outliers : 20.5880 % Variance is moderately inflated by
> outliers
>
> user=> (bench (accum-defun 1))
> Evaluation count : 44940 in 60 samples of 749 calls.
>  Execution time mean : 1.361631 ms
> Execution time std-deviation : 40.489537 µs
>Execution time lower quantile : 1.333474 ms ( 2.5%)
>Execution time upper quantile : 1.465123 ms (97.5%)
>Overhead used : 1.565276 ns
>
> Found 9 outliers in 60 samples (15. %)
> low-severe   1 (1.6667 %)
> low-mild 8 (13. %)
>  Variance from outliers : 17.3434 % Variance is moderately inflated by
> outliers
>
> ---
>
>
> On 5 Sep 2015, at 05:16, Amith George  wrote:
>
> Nice. Hadn't heard of it before. It looks interesting. The criterium
> benchmark is kinda disappointing though. The pattern matched function took
> nearly 15x the time of the normal function.
>
>
> --
> 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.
>



-- 
庄晓丹
Email:killme2...@gmail.com xzhu...@avos.com
Site:   http://fnil.net
Twitter:  @killme2008

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