def to_registration_result({:ok, res}) do
{:ok, %Membership.RegistrationResult{
success: res["success"],
message: res["message"],
new_id: res["new_id"],
validation_token: res["validation_token"],
authentication_token: res["authentication_token"]
}}
end
def to_registration_result({:error, err}) do
{:error, err}
end
(defmulti to-registration-result first)
(defmethod to-registration-result :ok
[[_ email password]]
(println email password))
(defmethod to-registration-result :err
[[_ err]]
(println "err: " err))def map_single({:ok, res}) do
cols = res.columns
[first_row | _] = res.rows
map_single {:cols_and_first, cols, first_row}
end
def map_single({:cols_and_first, cols, first_row}) do
zipped = List.zip([cols,first_row])
map_single {:zipped, zipped}
end
def map_single({:zipped, list}) do
{:ok, Enum.into(list, %{})}
end
def map_single({:error, err}) do
{:error, err}
end
--
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.
* 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.
--
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.
(defn- register
[db mailer email password]
(if (users/valid? email password)
(if (users/taken? db email)
(response/bad-request {:errors [{:message "That email is taken."}]})
(do (users/do-create! db email password)
(users/notify mailer email activate-subject activate-text)
(response/ok (auth/authenticate email))))
(response/bad-request {:errors [{:message errors/invalid-creds}]})))(defn register
([db mailer email password]
(register [:start {:db db :mailer mailer :email email :password password}]))
([status {:keys [db mailer email password] :as args}]
(cond
(= status :start)
(if (users/valid? email password)
(register [:check-unique args])
(register [:err {:res "Invalid credentials"}]))
(= status :check-unique)
(if (users/taken? db email)
(register [:create args])
(register [:err {:res "User already exisits"}]))
(= status :create)
(do (users/do-create! db email password)
(users/notify mailer email activate-subject activate-text)
(register [:ok {:res (auth/authenticate email)}]))
(= status :ok) (response/ok (:res args))
(= status :err) (response/bad-request {:errors [{:message (:res args)}]}))))
(defn register [& args] (register' (into [:start] args)))
(defun- register'
([:start db mailer email password]
(if (users/valid? email password)
(register' [:check-unique db mailer email password])
(register' [:err "Invalid credentials"])))
([:check-unique db mailer email password]
(if (users/taken? db email)
(register' [:create db mailer email password])
(register' [:err "User already exists"])))
([:create db mailer email password]
(do (users/do-create! db email password)
(users/notify mailer email activate-subject activate-text)
(register' [:ok (auth/authenticate email)])))
([:ok res] (response/ok (:res args)))
([:err msg] (response/bad-request {:errors [{:message (:res args)}]}))) ([:start _ _ email password]
(if (users/valid? email password)
(register' (into [:check-unique] it)
(register' [:err "Invalid credentials"])))
>> Thanks, it helps to know using a tagged vector is a real pattern :)I don't know that it's a "real pattern". If I saw code like this in production I would probably raise quite a stink about it during code reviews. It's a cute hack, but it is also an abuse of a data structure. Now when I see [:foo 42] I don't know if I have a vector of data or a tagged value. It's a better idea IMO to use something like deftype or defrecord to communicate the type of something. I'd much rather see #foo.bar.Age{:val 42} than [:foo.bar/age 42]. At least then when I do (type val) I don't get clojure.lang.PersistentVector.
So given that, if we want to represent a single key/value pair, the most natural way to do it would be:
[:foreground #color/rgb "ff0000"]
Variants fulfil the same purpose as key/value pairs in a map. The key denotes a context-sensitive purpose for the data, rather than its type.
{:type :pickup :store-id 123
:address nil
:email nil}
{:pickup {:store-id 123}
:digital nil
:delivery nil}
--
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.
>> "Variants fulfil the same purpose as key/value pairs in a map. The key denotes a context-sensitive purpose for the data, rather than its type."Then use a key/value type. That's my problem with this approach, it abuses a collection type and therefore creates confusion as to the type of data is contains.
That way I won't accidentally use the variant with conj, concat, count, pop, push, or the dozens of other vector functions that don't apply to variants at all.
You also can't extend protocols to them without also applying those protocols to vectors of all sizes.
In addition a variant deftype (or record) will only need 1 allocation each time you create it. Doing [:foo :bar] requires two allocations: one for the vector, and one for the tail array. In addition it imposes another pointer deref on every access as you have to jump from the type to the tail array to the value.
All in all, I see very little reason to use vectors as variants instead of a custom type, it complicates the code, and makes it harder to understand. Vectors aren't always vectors...they could also be variants?
--
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.
>> 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.
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.
Could you elaborate on what you mean by variants being like a key value pair?
On 6 September 2015 at 15:38, Timothy Baldridge <tbald...@gmail.com> 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:
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.
(def Recipient
(s/either PlaceHolder
Existing
OneOff))
(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?
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.
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.
--
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 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 a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/cuHfhVVE2zg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.
If you look at these implementations(def OneOff [(s/one s/Str 'name) (s/one s/Str 'email)])(s/defrecord OneOff[name :- s/Stremail :- s/Str])(defrecord OneOff [name email])All of them do more or less the same thing, just different. Clojure has really good support for records and they feel natural to me. I don't need to remember that :email is the second field. So I can do (:email one-off) instead of (get one-off 1). Remembering the positions can get tedious and very error prone over time. Always remember that software evolves over time.(:email one-off) still works if my data changes to (defrecord OneOff [name note email]), the vector version doesn't. Referring to things by name is a good thing.
For instance, which one of these to you consider to be the best representation of a event to set the expiry time:[:cache/expire #inst "2015-09-08T12:00:00Z"]{:type :cache/expire, :value #inst "2015-09-08T12:00:00Z"}#cache.Expire [#inst "2015-09-08T12:00:00Z"]#cache.Expire {:value #inst "2015-09-08T12:00:00Z"}