Sean Devlin
未读,2009年8月22日 14:24:432009/8/22登录即可回复作者
登录即可转发
您无权在此群组中删除帖子
请登录以举报消息
要么此群组的电子邮件地址为匿名状态,要么您得查看成员电子邮件地址权限才能查看原始帖子
收件人 Clojure Dev
Well, as promised here is round two of my proposed additions to
contrib. Today's thread is about the map-utils namespace.
Higher Order Functions
All the higher order functions in clojure accept and return a seq. It
is common to transform the resulting seq into a hash map.
These are a few functions that do this for you automatically.
Let's create a map for example purposes.
user=> (def abc123 {"a" 1 "b" 2 "c" 3})
#'user/abc123
* map-vals
This is like the `map` operator, but it applies `f` to every value of
the hash map instead of the entry. It returns a hash map.
user=> (map-vals #(* 2 %) abc123)
{"c" 6, "b" 4, "a" 2}
* map-keys
This is like the `map` operator, but it applies `f` to every key of
the hash map instead of the entry. It returns a hash map.
user=> (map-keys keyword abc123)
{:c 3, :b 2, :a 1}
* filter-map
This behaves just like `filter`. `pred` is applied to each entry of
the hash-map, and the resulting collection is transformed into a hash
map.
user=> (filter-map (comp even? second) abc123)
{"b" 2}
* remove-map
This behaves just like `remove`. `pred` is applied to each entry of
the hash-map, and the resulting collection is transformed into a hash
map.
user=> (remove-map (comp even? second) abc123)
{"a" 1, "c" 3}
#Tranforming a map
This section explores the `trans` closure, which is used to modify a
map.
* trans
I defined a function trans
(defn trans [& params]...)
Let me show an example:
user=> ((trans :count count) abc123)
{:count 3, "a" 1, "b" 2, "c" 3}
Notice the call to trans first, and then the result it applied to
test-
map. This is because trans generates a closure. In this case, it
applies the count function to the map, and associates it with the
key :count.
user=> ((trans "a" (comp inc #(get % "a"))) abc123)
{:a 1, :b "B", :c "C"}
* deftrans
trans is a little cumbersome, generating a closure. I also wrote a
deftrans macro. It creates a trans and stores it in the provided
name:
user=> (deftrans counter :count count)
#'user/counter
user=> (counter abc123)
{:count 3, "a" 1, "b" 2, "c" 3}
user=> (deftrans inc-a :a (comp inc :a))
#'user/inc-a
user=> (inc-a abc123)
{:a 1, :b "B", :c "C"}
* Using a closure
Let's revisit the fact that trans generates a closure. We can use
the
resulting transform anywhere we'd use a function.
### In a map
user=> (map counter (repeat 5 abc123))
({:count 3, "a" 1, "b" 2, "c" 3}
{:count 3, "a" 1, "b" 2, "c" 3}
{:count 3, "a" 1, "b" 2, "c" 3}
{:count 3, "a" 1, "b" 2, "c" 3}
{:count 3, "a" 1, "b" 2, "c" 3})
### In a comp
user=> ((comp counter counter) abc123)
{:count 4, "a" 1, "b" 2, "c" 3}
### In the STM
This is my favorite use of trans so far
user=> (def test-ref (ref abc123))
#'user/test-ref
user=> (dosync (alter test-ref counter))
{:count 3, "a" 1, "b" 2, "c" 3}
user=> @test-ref
{:count 3, "a" 1, "b" 2, "c" 3}
* trans*
The trans function associates its values after all the functions have
been evaluated
user=> ((trans :c1 count :c2 count :c3 count) abc123)
{:c3 3, :c2 3, :c1 3, "a" 1, "b" 2, "c" 3}
I have also defined the trans* closure, which associates the value in
the map between each iteration. I believe
this mimic the distinction between let & let* in CL, but I am unsure.
user=> ((trans* :c1 count :c2 count :c3 count) abc123)
{:c3 5, :c2 4, :c1 3, "a" 1, "b" 2, "c" 3}
That completes today's suggestions. Any thoughts?
Sean