This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-06-14
Channels
- # admin-announcements (2)
- # beginners (32)
- # boot (217)
- # cider (20)
- # cljsjs (25)
- # cljsrn (9)
- # clojure (87)
- # clojure-android (7)
- # clojure-austin (4)
- # clojure-belgium (10)
- # clojure-canada (13)
- # clojure-dev (28)
- # clojure-dusseldorf (2)
- # clojure-greece (119)
- # clojure-nl (1)
- # clojure-russia (22)
- # clojure-spain (3)
- # clojure-spec (81)
- # clojure-uk (54)
- # clojurescript (32)
- # community-development (2)
- # core-async (19)
- # cursive (18)
- # datascript (5)
- # datomic (1)
- # dirac (22)
- # emacs (22)
- # hoplon (198)
- # incanter (1)
- # instaparse (4)
- # jobs (3)
- # keechma (15)
- # ldnclj (2)
- # lein-figwheel (14)
- # mount (8)
- # om (78)
- # om-next (4)
- # onyx (37)
- # other-languages (1)
- # pedestal (6)
- # re-frame (22)
- # reagent (25)
- # ring-swagger (17)
- # robots (1)
- # slack-help (1)
- # spacemacs (7)
- # specter (50)
- # spirituality-ethics (3)
- # uncomplicate (5)
- # untangled (1)
- # yada (17)
@nathanmarz: With master, the transform
operation I typically try works. But, when loading com.rpl.specter.macros
it complains about the use of require
and eval
on lines 448 and 452. I’m wondering, though, is a transform
call sufficient to cover the new macroexpand code? (I suspect not, given require
and eval
being in the code paths that you probably want tested.)
@nathanmarz: Ahh… I found a call that will make it fail in bootstrap:
cljs.user=> (transform [(filterer odd?) LAST]
#_=> inc
#_=> [2 1 3 6 9 4 8])
⬆
undefined is not an object (evaluating 'com.rpl.specter.macros$macros.require.call') at line 1
@nathanmarz: It can be made to work in bootstrap by eliminating the require
and the eval. Perhaps macros.clj
would need to be converted to macros.cljx
or somesuch to pull it off. This bit of code worked:
(defn cljs-macroexpand [env form]
#_(require 'cljs.analyzer)
;; need to get the expansion function like this so that
;; this code compiles in a clojure environment where cljs.analyzer
;; namespace does not exist
(let [expand-fn cljs.analyzer/macroexpand-1
mform (expand-fn env form)]
(cond (identical? form mform) mform
(and (seq? mform) (#{'js*} (first mform))) form
:else (cljs-macroexpand env mform))))
and here it is working with those changes:
cljs.user=> (require-macros '[com.rpl.specter.macros :refer [transform]])
nil
cljs.user=> (require '[com.rpl.specter :refer [filterer LAST]])
nil
cljs.user=> (transform [(filterer odd?) LAST]
#_=> inc
#_=> [2 1 3 6 9 4 8])
[2 1 3 6 10 4 8]
Challenge
For all the keys in a map of maps, return a vector that has the key and all of the values of its value,
so
{:keep0 {:ignore :keep1, :ignore1 :keep2}}
->
[[:keep0 :keep1 :keep2]]
closest I’ve got is
(select [ALL (sp/collect-one sp/FIRST) LAST (sp/subselect MAP-VALS)] nested-map)
which gives me
[[:keep0 (:keep1 :keep2)]]
@conaw: (select [ALL (subselect (multi-path FIRST [LAST MAP-VALS]))] {:keep0 {:ignore :keep1, :ignore1 :keep2}})
@mfikes: with those changes does this code work?
(require '[com.rpl.specter :as s])
(require-macros '[com.rpl.specter.macros :refer [select transform traverse collected?]])
(select [s/VAL (collected? [v] (= v 1)) s/DISPENSE] 1)
should return [1]
@nathanmarz: Yes, I get [1]
in Planck, with no warnings with those proposed changes
great
should be able to fiddle with the code to get it working on all three platforms
@mfikes: ok, made the changes. let me know how it goes
@nathanmarz: Pulled down master of Specter and it’s a go for bootstrap with respect to trying out the select
above.
awesome
@nathanmarz: Continuing my efforts to understand; I wrote up some docs on the macros
namespace at https://github.com/codonnell/specter/wiki/List-of-Macros. I don't have all the macros in there yet and I'm not as confident in the accuracy of my descriptions. Again, it could be a starting point for documentation.
@codonnell: actually very accurate
the only thing I'd change is the example for defpathedfn
defpathedfn
is only meant for higher order navigators that take in paths as input
the ^:notpath
thing is if they also require a non-path param, for which transformed
is the only case of that
making a constructor function for a navigator which converts the constructor params to the navigator params is what defnavconstructor
is for
I would do that walk-pred
example like this:
(defnavconstructor walk-pred
[p walker]
[apred]
(p #(and (integer? %) (apred %))))
the difference between this definition and one using defpathedfn is the parameter to navconstructor walk-pred can be completely dynamic, and the path can still be factored/cached
@nathanmarz: "that itself takes in one or more paths as input" is even in my description (taken from Codox) of defpathedfn
. I'll remove that example and add your modified version in the to-be written defnavconstructor
. I wasn't sure of the purpose of defnavconstructor
, but your example makes it clearer.
Why is transformed
not implemented using defnavconstructor
?
because it takes in a path
navconstructor can only parameterize an existing navigator (either defined via defnav
or comp-paths
), it can't handle threading params into a nested path
have you read this post? https://github.com/nathanmarz/specter/wiki/Specter-0.11.0:-Performance-without-the-tradeoffs
I did, but I should definitely take a second look now that I have a better understanding of how specter operates.
yea, understanding the mechanics of factoring is the key to understanding these different macros
it all comes down to the fact that to precompile something you need a completely static path
specter's trick of threading parameters later using an array leads to all these different mechanisms for parameterization
Thanks for the suggestion. I'll read through it more carefully before proceeding further with the macro stuff.
sure thing, happy to answer more questions as they arise
appreciate that
the actual code that does the factoring may be helpful as well: https://github.com/nathanmarz/specter/blob/master/src/clj/com/rpl/specter/impl.cljx#L1385
"magic-precompilation" lol
Yeah, this post makes a lot more sense now I'm more familiar.
a reflection of my surprise when I first wrote this that this was actually possible 🙂
@nathanmarz: Just to confirm. magic-precompilation
returns the pair of precompiled path and function which sets the late-bound params mentioned in your post, right?
@codonnell: yes, though to be completely precise the function returns an array of late-bound params
Or an alternative way of atomically transforming several paths using transform or setval?
you can call (apply multi-path my-paths)
though if you want that to inline factor you should wrap it in this:
(defpathedfn multi-path* [paths]
(apply multi-path paths))
actually nvm, it won't be possible to inline factor that anyway
no it's a regular function
hence the fn
in defpathedfn