specter

Latest version: 1.1.3
sophiago 2018-05-19T00:45:59.000132Z

This is my first pass at doing this at much more naive level using the navigator you provided. Based on the output I'm clearly misunderstanding how this navigator identifies common roots.

sophiago 2018-05-19T00:48:58.000163Z

I'm just trying to get a feel for picking out the roots by applying it to input that just uses literal variables, e.g. %1, rather than an actual literal. But having it also expand ->> is making me unsure whether I'm placing all the functions correctly. Regardless, they definitely should not be all stacked at the top in order of the transform calls like that.

nathanmarz 2018-05-19T01:04:31.000086Z

it doesn't identify common roots

nathanmarz 2018-05-19T01:05:13.000057Z

that snippet was just to show doing a transformation that wraps after identifying the expression to wrap

sophiago 2018-05-19T01:18:04.000097Z

Okay, gotcha. I would think the way I'm recursing on it would at least update at the next level up, though. Right now they're at the top-level. I may just be confused by the expanded ->> though...

sophiago 2018-05-19T01:24:00.000083Z

Yup, it's the expansion of ->> that's throwing me. I'll pay around with this and probably come back when I have something that works but seems could be more efficient. Thanks, @nathanmarz !

sophiago 2018-05-19T17:57:44.000011Z

I'm still a bit confused about a navigator for this. I'm currently calling transform in multiple passes for each pattern and figure I can bypass having to find common root bindings by enforcing linearity but, e.g. (subselect TREE symbol? (selected? NAME pattern)), navigates to a vector containing the first symbol matching the pattern rather than the coll containing that symbol.

nathanmarz 2018-05-19T18:02:39.000021Z

subselect navigates to the result of running select on that path

nathanmarz 2018-05-19T18:02:41.000106Z

(select-any (subselect ALL :a even?) [{:a 1} {:a 2} {:a 4}])
;; => [2 4]

(transform (subselect ALL :a even?) reverse [{:a 1} {:a 2} {:a 4}])
;; => [{:a 1} {:a 4} {:a 2}]

sophiago 2018-05-19T18:04:46.000074Z

Sorry, seems I misread the docs. Is there a navigator that will act like contains? on lists?

nathanmarz 2018-05-19T18:05:36.000084Z

contains? doesn't work on lists

nathanmarz 2018-05-19T18:05:40.000118Z

since it's not keyed

sophiago 2018-05-19T18:06:07.000103Z

I know. I suppose like some

nathanmarz 2018-05-19T18:06:20.000126Z

you mean something like (selected? ALL even?) ?

sophiago 2018-05-19T18:08:08.000086Z

I suppose if I could replace even? with a pattern and then navigate to top-most coll containing the pattern?

sophiago 2018-05-19T18:08:46.000024Z

I'm realizing using let bindings for linearity throws a wrench in that, but I should be able to figure it out. Seems easier than finding common roots.

sophiago 2018-05-19T18:12:13.000052Z

I would think I could just do (collect TREE (selected? symbol? NAME pattern)) where TREE navigates to every coll, but then it just stops at the top level every time.

nathanmarz 2018-05-19T18:26:42.000101Z

if TREE navigates to collections, then that selected? clause will always fail

sophiago 2018-05-19T18:28:06.000049Z

Ah, well that does seem to be what's happening. You're implying I could have it navigate to every item? I was thinking maybe I should just use a zipper and then could specify relative paths once a pattern is matched.

nathanmarz 2018-05-19T18:28:12.000136Z

user=> (setval (selected? symbol?) :replaced ['a 2 'b])
[a 2 b]
user=> (setval (selected? ALL symbol?) :replaced ['a 2 'b])
:replaced

sophiago 2018-05-19T18:30:27.000038Z

If I can combine zipper navigators with regular ones then it would seem something like [TREE symbol? NAME pattern z/UP] might be the simplest way to do this.

sophiago 2018-05-19T18:36:22.000036Z

Yup, reading now.

sophiago 2018-05-19T18:41:19.000075Z

I'm just uncertain whether zipper navigators can be combined with regular ones. It'd be much easier in this case than using predfns.

sophiago 2018-05-19T18:42:46.000103Z

The answer would seem to be no based on the examples

nathanmarz 2018-05-19T19:05:56.000053Z

zipper navigators operate on zipper data structures

nathanmarz 2018-05-19T19:06:32.000109Z

use navigators like VECTOR-ZIP and NODE to navigate in and out of zippers

sophiago 2018-05-19T19:18:44.000064Z

The structure that zippers return doesn't seem to make them ideal for use with transform though. I'm having some luck with [ALL seq? (fn [x] some #(= % (symbol pattern)) x)]: on the first pass it at least matches the seq immediately above the pattern.

nathanmarz 2018-05-19T19:28:13.000044Z

you generally don't navigate to a zipper data structure for the transform fn, you use NODE to navigate into the value the zipper is currently pointing at

sophiago 2018-05-19T19:33:17.000079Z

If I use NODE then it again locates the pattern rather than the seq containing the pattern, though.

sophiago 2018-05-19T19:33:52.000012Z

So (select [SEQ-ZIP (find-first #(= % (symbol "%"))) NODE] (list (list '% 'foo))) => [%] rather than (% foo)

sophiago 2018-05-19T19:35:46.000107Z

And if I use (select [SEQ-ZIP (find-first #(= % (symbol "%"))) UP] (list (list '% 'foo))) then it's not really in a form that I can call transform on.

sophiago 2018-05-19T19:37:05.000123Z

I really just want something like [TREE symbol? NAME #"%"] except navigating to the seq containing the pattern.

sophiago 2018-05-19T19:40:18.000013Z

Obviously I can call ffirst on the zipper version, but that doesn't really help if I want to transform it preserving the structure it's in.

nathanmarz 2018-05-19T20:59:22.000081Z

@sophiago how is [SEQ-ZIP (find-first #(= % (symbol "%"))) UP NODE] not exactly what you want?

nathanmarz 2018-05-19T20:59:32.000091Z

it navigates to (% foo)

nathanmarz 2018-05-19T21:01:07.000016Z

user=> (transform [SEQ-ZIP (find-first #(= % (symbol "%"))) UP NODE]
  #_=>   (fn [expr]
  #_=>     `(:wrapped ~expr))
  #_=>   '(+ 1 (% foo)))
(+ 1 (:wrapped (% foo)))

sophiago 2018-05-19T21:01:50.000081Z

I think I neglected to try that combination 😕

sophiago 2018-05-19T21:01:59.000030Z

One sec, I'm trying it in the transform

sophiago 2018-05-19T21:05:06.000085Z

I think that's it 🙂

sophiago 2018-05-19T21:06:35.000006Z

Oh, it's missing patterns inside let bindings. I knew that would be an issue when I decided on linearity

sophiago 2018-05-19T21:11:18.000067Z

I think it may just work out that the bindings are at common roots as long as I call setval separately instead of from inside transform

nathanmarz 2018-05-19T21:17:05.000093Z

fyi you can rewrite the transform like this:

(transform
  [SEQ-ZIP
   (find-first #(= % (symbol pattern)))
   UP
   NODE
   (transformed [TREE symbol? NAME (re-pattern pattern)]
     (fn [_] (str fresh-var)))]
  #(list `fn* [fresh-var] %)
  x)

👍 1
sophiago 2018-05-19T21:32:11.000028Z

Yeah, the common roots issue is difficult and I can't get around it by using let bindings with linearity. But there's something deeper to say about what structures allow this navigator to finds them anyway and structures that cause trouble. Like I have one where a bound variable repeats and it's wrapped correctly and one where it's not. I tend to think the latter could be solved with destructuring in the example.

sophiago 2018-05-19T21:36:44.000026Z

I think it actually comes down to currying. The one where it doesn't naturally find a root needs to be a binary function for map-indexed. Calling first and second after interleaving and partitioning to use plain map creates the same type of structure.