Fork me on GitHub
#specter
<
2016-06-14
>
mfikes01:06:31

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

mfikes01:06:08

@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

mfikes01:06:53

(I hear the profanity from here.)

mfikes01:06:18

@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]

conaw10:06:20

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)]]

nathanmarz12:06:03

@conaw: (select [ALL (subselect (multi-path FIRST [LAST MAP-VALS]))] {:keep0 {:ignore :keep1, :ignore1 :keep2}})

nathanmarz12:06:30

@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)

nathanmarz12:06:57

should return [1]

mfikes12:06:36

@nathanmarz: Yes, I get [1] in Planck, with no warnings with those proposed changes

nathanmarz12:06:01

should be able to fiddle with the code to get it working on all three platforms

nathanmarz12:06:29

@mfikes: ok, made the changes. let me know how it goes

mfikes12:06:47

@nathanmarz: Pulled down master of Specter and it’s a go for bootstrap with respect to trying out the select above.

codonnell21:06:54

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

nathanmarz21:06:07

@codonnell: actually very accurate

nathanmarz21:06:16

the only thing I'd change is the example for defpathedfn

nathanmarz21:06:38

defpathedfn is only meant for higher order navigators that take in paths as input

nathanmarz21:06:59

the ^:notpath thing is if they also require a non-path param, for which transformed is the only case of that

nathanmarz21:06:32

making a constructor function for a navigator which converts the constructor params to the navigator params is what defnavconstructor is for

nathanmarz21:06:14

I would do that walk-pred example like this:

(defnavconstructor walk-pred
  [p walker]
  [apred]
  (p #(and (integer? %) (apred %))))

nathanmarz21:06:12

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

codonnell21:06:53

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

codonnell21:06:05

Why is transformed not implemented using defnavconstructor?

nathanmarz21:06:21

because it takes in a path

nathanmarz21:06:03

navconstructor can only parameterize an existing navigator (either defined via defnav or comp-paths), it can't handle threading params into a nested path

codonnell21:06:44

I did, but I should definitely take a second look now that I have a better understanding of how specter operates.

nathanmarz21:06:11

yea, understanding the mechanics of factoring is the key to understanding these different macros

nathanmarz21:06:41

it all comes down to the fact that to precompile something you need a completely static path

nathanmarz21:06:10

specter's trick of threading parameters later using an array leads to all these different mechanisms for parameterization

codonnell21:06:51

Thanks for the suggestion. I'll read through it more carefully before proceeding further with the macro stuff.

nathanmarz22:06:09

sure thing, happy to answer more questions as they arise

codonnell22:06:48

appreciate that

codonnell22:06:05

"magic-precompilation" lol

codonnell22:06:26

Yeah, this post makes a lot more sense now I'm more familiar.

nathanmarz22:06:27

a reflection of my surprise when I first wrote this that this was actually possible 🙂

codonnell22:06:39

@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?

nathanmarz22:06:45

@codonnell: yes, though to be completely precise the function returns an array of late-bound params

mac23:06:17

Is there a way of passing a vector of paths to multi-path?

mac23:06:33

Or an alternative way of atomically transforming several paths using transform or setval?

nathanmarz23:06:11

you can call (apply multi-path my-paths)

nathanmarz23:06:28

though if you want that to inline factor you should wrap it in this:

(defpathedfn multi-path* [paths]
  (apply multi-path paths))

mac23:06:53

Oh, I thought multi-path was a macro?

nathanmarz23:06:57

actually nvm, it won't be possible to inline factor that anyway

nathanmarz23:06:08

no it's a regular function

nathanmarz23:06:26

hence the fn in defpathedfn

mac23:06:41

Ah silly me, it is just defined by a macor