Ok Here is what i am trying to do
(defn addresses [person-id]
;addresses-retrival )
(defn person [id]
(merge {:addresses (addresses id)} {:name "john"}))
In the above person function i want addresses to be retrieved only on demand , like only when i do
(:addresses (person 10))
and not when
(person 10)
I am not sure if i am going about this right, being new to clojure.
You can use delay.
(defn person [id]
(delay {:addresses (addresses id) :name "john"}))
(person 2) will then return a delayed, without evaluating anything.
To access the content and evaluate the delayed object, use force or deref (or #).
(:addresses #(person 5))
Alternatively, you can put the delay on the address only.
(defn person [id]
{:addresses (delay (addresses id)) :name "john"})
which can be nicer depending on your problem.
It allows to define:
(defn get-address [person]
#(:address person))
Which will get the delayed address and force it.
(Forcing means computing the first time and retrieving the forced result any other times).
At least as far as sequences go, clojure is pretty damned lazy without needed to be told.
Here, modelling your address-retrieval as counting, try:
(defn addresses [person-id]
(iterate #(do (println %) (inc %)) person-id))
(defn person [id]
(merge {:addresses (addresses id)} {:name "john"}))
(def people (map person (range 100)))
So far it won't have printed anything, but if you say:
(doall (take 5 (:addresses (nth people 10))))
Then you should see the printing happen in exactly the cases that need to happen to count up five in the tenth place. I'd imagine that might be the sort of behaviour you want?
So get your address lookup to produce a lazy sequence (map, filter, reduce will all do)
You can return a function from the addresses function which when later called will retrieve the addresses. Something like this:
(defn addresses [person-id]
#(;addresses-retrival))
(defn person [id]
(merge {:addresses ((addresses id))} {:name "john"}))
Note than the addresses function returns an anonymous function (created using #) and the person function calls that anonymous function using an extra pair of parens.
I can suggest something close to what you expect.
; Note the use of anonymouns function. #(addresses id)
(defn person [id]
(merge {:addresses #(addresses id)} {:name "john"}))
; :addresses returns a function. Evaluate it by wrapping it in another set of parans.
((:addresses (person 10)))
Remember that Delays are memoized, so successive calls of your addresses delay will always yield the same address as the first time you derefed the Delay.
(defn addresses [person-id]
{:home (str (rand-int 100) " Cool St.") :work "1243 Boring St."})
(defn person [id]
(merge {:addresses (delay (addresses id))} {:name "john"}))
(let [person1 (person 1)]
(println #(:addresses person1))
(println #(:addresses person1)))
This will print:
{:home 65 Cool St., :work 1243 Boring St.}
{:home 65 Cool St., :work 1243 Boring St.}
Notice how the home address is unchanged on the second deref of the delay.
If you don't want this behavior you need to use a function closure instead.
(defn addresses [person-id]
{:home (str (rand-int 100) " Cool St.") :work "1243 Boring St."})
(defn person [id]
(merge {:addresses (fn [] (addresses id))} {:name "john"}))
(let [person1 (person 1)]
(println ((:addresses person1)))
(println ((:addresses person1))))
This will print:
{:home 16 Cool St., :work 1243 Boring St.}
{:home 31 Cool St., :work 1243 Boring St.}
Notice how the home address was different on the sub-sequent call to the closure.
So, if you're addresses function does side-effect, say fetches addresses from a database. And the persons can change their addresses, and you'd want your code to always have the most recent address, it's something to keep in mind if Delay works for you, or if a function closure would be a better candidate.
Related
Let's say I have an atom:
(def pets (atom { :cats {} :dogs {} }))
I want to watch this atom for changes, so I create a watcher:
(add-watch pets :pet-watcher
(fn [r k os ns]
(when (not= os ns
(println (str "Pets updated: " ns) )))))
Now, if I update my pets atom, I get notified of changes:
(swap! pets assoc-in [:dogs] {:name "Sparky" :color "Brown"})
; Pets updated: {:cats {}, :dogs {:name "Sparky", :color "Brown"}}
But what if I only want to be notified if :cats changes? I get an error when I try to compare properties of deref'd atoms:
; THIS DOES NOT WORK
(add-watch pets :cat-watcher
(fn [r k os ns]
(when (not= (:cats #os) (:cats #ns)
(println (str "Cats updated: " (:cats #ns)) )))))
(swap! pets assoc-in [:cats] {:name "Whiskers" :color "Orange"})
; Error: No protocol method IDeref.-deref defined for type cljs.core/PersistentArrayMap
There must certainly be an elegant way to compare values with the same key across two atoms. How would you update my :cat-watcher to notify me of changes to just :cats?
There is only one atom in your example.
You don't need to dereference os and ns in a watching function since it gets the old and new values of the atom not the atom itself. Just remove the # signs in your code.
The below code I have found from a book (Functional Programming Patterns in Scala and Clojure). The for statement uses close-zip? to filter out people outside of the zips and then it generates a greeting to the people who are left. However, I am not quite sure how people should look like as argument for generate-greetings and print-greetings functions?
(def close-zip? #{19123 19103})
(defn generate-greetings [people]
(for [{:keys [name address]} people :when (close-zip? (address :zip-code))]
(str "Hello, " name ", and welcome to the Lambda Bar And Grille!")))
(defn print-greetings [people]
(doseq [{:keys [name address]} people :when (close-zip? (address :zip-code))]
(println (str "Hello, " name ", and welcome to the Lambda Bar And Grille!"))))
They need to be maps with :name and :address keys, like:
{:name "A Person", :address {:zip-code 19103}}
for will take each element from people and assign each one to {:keys [name address]}. This is called destructuring, and it's just a convenience. It's the same as saying:
(for [person people
:let [name (:name person)
address (:address person)]
:when (close-zip? (:zip-code address))]
(str ...))
I've got two databases that I'm attempting to keep in sync using a bit of Clojure glue code.
I'd like to make something like a clojure.set/difference that operates on values projected by a function.
Here's some sample data:
(diff #{{:name "bob smith" :favourite-colour "blue"}
{:name "geraldine smith" :age 29}}
#{{:first-name "bob" :last-name "smith" :favourite-colour "blue"}}
:name
(fn [x] (str (:first-name x) " " (:last-name x))))
;; => {:name "geraldine smith" :age 29}
The best I've got is:
(defn diff
"Return members of l who do not exist in r, based on applying function
fl to left and fr to right"
[l r fl fr]
(let [l-project (into #{} (map fl l))
r-project (into #{} (map fr r))
d (set/difference l-project r-project)
i (group-by fl l)]
(map (comp first i) d)))
But I feel that this is a bit unwieldly, and I can't imagine it performs very well. I'm throwing away information that I'd like to keep, and then looking it up again.
I did have a go using metadata, to keep the original values around during the set difference, but I can't seem put metadata on primitive types, so that didn't work...
I'm not sure why, but I have this tiny voice inside my head telling me that this kind of operation on the side is what monads are for, and that I should really get around to finding out what a monad is and how to use it. Any guidance as to whether the tiny voice is right is very welcome!
(defn diff
[l r fl fr]
(let [r-project (into #{} (map fr r))]
(set (remove #(contains? r-project (fl %)) l))))
This no longer exposes the difference operation directly (it is now implicit with the remove / contains combination), but it is succinct and should give the result you are looking for.
example usage and output:
user> (diff #{{:name "bob smith" :favourite-colour "blue"}
{:name "geraldine smith" :age 29}}
#{{:first-name "bob" :last-name "smith" :favourite-colour "blue"}}
:name
(fn [x] (str (:first-name x) " " (:last-name x))))
#{{:age 29, :name "geraldine smith"}}
I have a function that begins like this:
(defn data-one [suser]
(def suser-first-name
(select db/firstNames
(fields :firstname)
(where {:username suser})))
(def suser-middle-name
(select db/middleNames
(fields :middlename)
(where {:username suser})))
(def suser-last-name
(select db/middleNames
(fields :lastname)
(where {:username suser})))
;; And it just continues on and on...
)
Of course, I don't like this at all. I have this pattern repeating in many areas in my code-base and I'd like to generalize this.
So, I came up with the following to start:
(def data-input {:one '[suser-first-name db/firstNames :firstname]
'[suser-middle-name db/middleNames :middlename]
'[suser-last-name db/lastNames :lastname]})
(defpartial data-build [data-item suser]
;; data-item takes the arg :one in this case
`(def (data-input data-item)
(select (data-input data-item)
(fields (data-input data-item))
(where {:username suser}))))
There's really a few questions here:
-- How can I deconstruct the data-input so that it creates x functions when x is unknown, ie. that the values of :one is unknown, and that the quantities of keys in data-input is unknown.
-- I'm thinking that this is a time to create a macro, but I've never built one before, so I am hesitant on the idea.
And to give a little context, the functions must return values to be deconstructed, but I think once I get this piece solved, generalizing all of this will be doable:
(defpage "/page-one" []
(let [suser (sesh/get :username)]
(data-one suser)
[:p "Firat Name: "
[:i (let [[{fname :firstname}] suser-first-name]
(format "%s" fname))]
[:p "Middle Name: "
[:i (let [[{mname :emptype}] suser-middle-name]
(format "%s" mname))]
[:p "Last Name: "
[:i (let [[{lname :months}] suser-last-name]
(format "%s" lname))]]))
Some suggestions:
def inside a function is really nasty - you are altering the global environment, and it can cause all kinds of issues with concurrency. I would suggest storing the results in a map instead.
You don't need a macro here - all of the data fetches can be done relatively easily within a function
I would therefore suggest something like:
(def data-input [[:suser-first-name db/firstNames :firstname]
[:suser-middle-name db/middleNames :middlename]
[:suser-last-name db/lastNames :lastname]])
(def data-build [data-input suser]
(loop [output {}
items (seq data-input)]
(if items
(recur
(let [[kw db fieldname] (first items)]
(assoc output kw (select db (fields fieldname) (where {:username suser}))))
(next items))
output)))
Not tested as I don't have your database setup - but hopefully that gives you an idea of how to do this without either macros or mutable globals!
Nice question. First of all here's the macro that you asked for:
(defmacro defquery [fname table fields ]
(let [arg-name (symbol 'user-name)
fname (symbol fname)]
`(defn ~fname [~arg-name]
(print ~arg-name (str ~# fields)))))
You can call it like that:
(defquery suser-first-name db/firstNames [:firstname])
or if you prefer to keep all your configurations in a map, then it will accept string as the first argument instead of a symbol:
(defquery "suser-first-name" db/firstNames [:firstname])
Now, if you don't mind me recommending another solution, I would probably chose to use a single function closed around configuration. Something like that:
(defn make-reader [query-configurations]
(fn [query-type user-name]
(let [{table :table field-names :fields}
(get query-configurations query-type)]
(select table
(apply fields field-names)
(where {:username suser})))))
(def data-input {:firstname {:table db/firstNames :fields :firstname}
:middlename {:table db/middleNames :fields :middlename}
:lastname {:table db/lastNames :fields :lastname}})
(def query-function (make-reader data-input))
;; Example of executing a query
(query-function :firstname "tom")
By the way there's another way to use Korma:
;; This creates a template select from the table
(def table-select (select* db/firstNames))
;; This creates new select query for a specific field
(def first-name-select (fields table-select :firstname))
;; Creating yet another query that filters results by :username
(defn mkselect-for-user [suser query]
(where query {:username suser}))
;; Running the query for username "tom"
;; I fully specified exec function name only to show where it comes from.
(korma.core/exec (mkselect-for-user "tom" first-name-select))
For more information I highly recommend looking at Korma sources.
This is a follow-up to my earlier question.
I came up with a bizarre object scheme from my reading of Let Over Lambda and can think of no advantages over protocols, but want to get opinions. I am just exploring the use of higher-order functions and encapsulation.
(defn new-person
"Construct a new Person object and return a Map of accessor methods."
[init-first-name init-last-name init-age]
(let [first-name (ref init-first-name)
last-name (ref init-last-name)
age (ref init-age)]
{:get-first-name #(#first-name)
:set-first-name #(dosync (ref-set first-name %1))
:get-last-name #(#last-name)
:set-last-name #(dosync (ref-set last-name %1))
:get-age #(#age)
:set-age #(dosync (ref-set age %1))}))
I can use the object like this:
(def fred (new-person "fred" "flintstone" 42))
and retrieve an accessor method this way:
(fred :get-age)
but I can't figure out how to call the accessor.
The object created is thread-safe since all mutation of "instance" variables occurs in the STM.
UPDATE: New and improved version:
(defn new-person
"Construct a new Person object and return a Map of accessor methods."
[init-first-name init-last-name init-age]
(let [first-name (ref init-first-name)
last-name (ref init-last-name)
age (ref init-age)]
{:first-name
(fn
([] #first-name)
([val] (dosync (ref-set first-name val))))
:last-name
(fn
([] #last-name)
([val] (dosync (ref-set last-name val))))
:age
(fn
([] #age)
([val] (dosync (ref-set age val))))}))
Maybe not a 100 % answer to your question, but would you try to do is not very idiomatic for Clojure. The 'standard' solution would be something like:
(defrecord Person [first-name last-name age])
(def fred (Person. "fred" "flintstone" 42))
(fred :age)
It looks like you are forcing OO mutable state into Clojure 'objects'
Its the same as your follow up question, wrap the form in another set of parenthesis. When an inner form returns a function, its the same as a symbol that returns a function. The rule is the first form in a parenthesis will always be looked up as a special form, macro, or function. You need something like quote to prevent this behavior.
user=> (fred :get-age)
#<user$new_person$fn__531 user$new_person$fn__531#c4afc4>
user=> ((fred :get-age))
42
Its the same as
user=> (let [age-getter (fred :get-age)] (age-getter))
42
Clojure philosophy is NOT to encapsulate access to the record fields themselves. Encapsulation should happen on higher levels, for example in the set of functions that work with that records. See Clojure - datatypes:
Encapsulation of information is folly fields are public, use protocols/interfaces to avoid dependencies