Fork me on GitHub
#specter
<
2016-06-10
>
conaw12:06:58

Alright, here’s another challenge. Let me know if this is just taking the idea of everything as a navigation too far though. Given this [[1 2] [1 3] [3 4] [4 5] [5 6]]

conaw12:06:15

Could you express this

conaw12:06:17

(for [[k v] e] {k #{v}}) (apply merge-with clojure.set/union))

conaw12:06:25

as a transformation

conaw12:06:40

or rather as a navigation

conaw12:06:26

especially if you’re planning on going back to tuples

conaw12:06:33

copy paste was off as well

conaw12:06:34

(->> (for [[k v] e] {k #{v}}) (apply merge-with clojure.set/union))

nathanmarz13:06:13

I mean, you can

nathanmarz13:06:53

but it's not particularly better than the manual code since everything in the structure is used

nathanmarz13:06:35

(require '[clojure.set :as set])

(defnav MERGED-MAPS []
  (select* [this structure next-fn]
    ;;TODO: fill this in
    )
  (transform* [this structure next-fn]
    (apply merge-with (fn [& vals] (next-fn vals)) structure)
    ))


(transform
  [(parser #(transform ALL (fn [[k v]] {k #{v}}) %) #(vec %))
   MERGED-MAPS]
  #(apply set/union %)
  [[1 2] [1 3] [3 4] [4 5] [5 6]])

nathanmarz13:06:55

that outputs [[1 #{3 2}] [3 #{4}] [4 #{5}] [5 #{6}]]

conaw14:06:07

cool, just trying to get a sense of where the edge is

conaw14:06:09

are there other examples of when you’d use parser?

conaw14:06:18

didn’t see that mentioned in any doc?

nathanmarz15:06:32

@conaw It's most commonly used for something like this:

(def LONG-PARSER (parser #(Long/parseLong %) str))

(transform [ALL LONG-PARSER] inc ["10" "1" "0"])
;; => ["11" "2" "1"]

nathanmarz15:06:47

the docs are very incomplete, though most of the public API has docstrings

conaw15:06:38

ok, here’s a question. Is there a way I could do a transform that would be akin to map-indexed. (transform [TOPSORT :position-id (subset #{})] (fn [x] something that gives me an unique value in the range of zero to the number of items I’m doing the select on) tree)

conaw15:06:25

the function for transform is only getting access to one selected value at a time right

conaw15:06:21

so you’d have to do something like, pass the whole subsequence of values you want as a sequence, and then put them all back in in the right place

nathanmarz16:06:18

I think you're looking for subselect

nathanmarz16:06:17

(transform (subselect ALL even?) reverse [1 2 3 4 5 6 7]) -> [1 6 3 4 5 2 7]

conaw16:06:15

(transform [(sp/subselect ALL map? :position)] (partial map-indexed (fn [i x] i)) [{:a 1 😛 1}[:not :me 1]{:b 2}])

conaw16:06:21

(transform [(sp/subselect ALL map? :position)] 
           (partial map-indexed (fn [i x] i)) 
           [{:a 1 :b 1}[:not :me 1]{:b 2}])

conaw16:06:41

[{:a 1, 😛 1, :position 0} [:not :me 1] {:b 2, :position 1}]

conaw16:06:53

returns

[{:a 1, :b 1, :position 0} [:not :me 1] {:b 2, :position 1}]

conaw16:06:05

much appreciated

conaw16:06:44

this is really beautiful the more I’m exploring it

conaw16:06:53

thanks so much for the help

nathanmarz16:06:58

I think you can do that last one with this transform-fn: (fn [aseq] (range (count aseq)))

nathanmarz16:06:06

a little cleaner in my opinion

nathanmarz16:06:37

@conaw: or even better:

(transform [(subselect ALL map? :position) (view count)] 
           range
           [{:a 1 :b 1} [:not :me 1] {:b 2}])

conaw16:06:03

very cool

conaw16:06:25

if you’d like, happy to take a stab at writing up some examples for the wiki.

nathanmarz16:06:42

that would be awesome

conaw16:06:20

will give it a stab

conaw16:06:38

taking the subselect example into recursion

conaw16:06:22

nevermind, actually works just as expected

conaw16:06:27

this is very cool

nathanmarz16:06:51

yea subselect is pretty magical

aengelberg16:06:47

its end result almost outweighs the mutable hackiness I used to achieve it 🙂

conaw16:06:52

lol, I was trying to figure out how I would even achieve this before @nathanmarz mentioned subselect, only thing I could think of was to create an atom

conaw16:06:23

glad you went into the swamp for us!

aengelberg16:06:54

I like this quote from http://clojure.org/transients:

If a tree falls in the woods, does it make a sound?
If a pure function mutates some local data in order to produce an immutable return value, is that ok?

conaw16:06:21

so much beauty in this channel

nathanmarz16:06:14

that's a good one

nathanmarz16:06:27

been digging into clojure's transducers and they use a lot of mutability

aengelberg16:06:50

Subselect gets awkward when working with sets:

(subselect [ALL ALL] reverse [#{1 2 3} [4 5 6]])
=>
[#{6 5 4} [???]]

nathanmarz16:06:04

looks reasonable to me

aengelberg16:06:32

often I get overly paranoid about confusing beginners

nathanmarz16:06:53

I know what you mean

nathanmarz16:06:14

but I like the clojure philosophy of keep it simple and well defined

nathanmarz16:06:20

even if it requires a learning curve

nathanmarz17:06:53

a lot of overlap with transducers

aengelberg17:06:40

yeah, just saw that. Seems like it could be even more useful if takenav could reset at a later level, e.g. (select [ALL ALL (takenav 3)] [[1 2 3 4 5] [6 7 8 9 10]]) => [[1 2 3] [6 7 8]]

aengelberg17:06:05

essentially the volatile would need to get reset in between the two ALLs

nathanmarz17:06:36

i think the result you would expect there is [1 2 3 6 7 8]

nathanmarz17:06:47

you might want both behaviors

aengelberg17:06:51

correct, sorry

aengelberg17:06:13

thus proving that it's unreasonable to expect that behavior arbitrarily 🙂

nathanmarz17:06:19

so resetting would be an explicit choice

aengelberg17:06:39

have you considered simply introducing (ALL-transduce (take 3))

nathanmarz17:06:18

that would be one way to do it

nathanmarz17:06:30

then takenav would be a completely different implementation to that

nathanmarz17:06:45

seems like they should unify more cleanly

nathanmarz17:06:57

the degree of overlap is very suspicious

aengelberg17:06:57

or maybe a "take view"

nathanmarz17:06:59

could be something like (select [ALL ALL (traversed (takenav 3)] ... )

aengelberg17:06:26

(transform [ALL (subselect (taken 3))] [[1 2 3 4 5] [6 7 8 9 10]]) => [[1 2 3] [6 7 8]]

aengelberg17:06:34

uhhhh ignore that

aengelberg17:06:56

(transform [ALL (subselect (taken 3))] inc [[1 2 3 4 5] [6 7 8 9 10]]) => [[2 3 4 4 5] [7 8 9 9 10]]

nathanmarz17:06:23

with the idea there that subselect re-parameterizes its path on every invocation?

nathanmarz17:06:31

that's what I was thinking with traversed

nathanmarz17:06:59

either way the semantics are pretty subtle

nathanmarz17:06:04

maybe too subtle

conaw17:06:47

hey @nathanmarz @aengelberg total aside, but don’t suppose either of you guys know of any great lecturers or youtube channels/videos relating to graph theory.

nathanmarz17:06:18

looks like tim roughgarden has a bunch of videos on graph algorithms on youtube

nathanmarz17:06:28

he's the best teacher I ever had

aengelberg17:06:21

I was suggesting taken would be just a regular (not stateful) navigator that only selects or transforms the first N elements

aengelberg17:06:30

less performant though to do a subselect

nathanmarz18:06:02

@aengelberg: ah, yea I'm thinking more cases like [ALL ALL ALL (takenav 3)]

aengelberg18:06:16

too many ALLs 🙂

nathanmarz18:06:37

(select [ALL (freshpath ALL (take-nav 2)) (take-nav 4)]
  [[1] [2 3 4] [5 6 7]])
;; => [1 2 3 5]

nathanmarz18:06:51

"freshpath" would mean to treat that path from scratch

nathanmarz18:06:26

the only impact that would have would be to initialize the states and collected vals every time it enters that part of the path