This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-08
Channels
- # adventofcode (240)
- # beginners (87)
- # boot (4)
- # cider (27)
- # cljs-dev (20)
- # cljsrn (24)
- # clojure (365)
- # clojure-argentina (1)
- # clojure-brasil (4)
- # clojure-dev (12)
- # clojure-greece (65)
- # clojure-india (1)
- # clojure-italy (15)
- # clojure-japan (1)
- # clojure-losangeles (1)
- # clojure-madison (4)
- # clojure-poland (3)
- # clojure-russia (5)
- # clojure-spec (3)
- # clojure-uk (105)
- # clojurescript (27)
- # core-async (1)
- # core-logic (3)
- # cursive (61)
- # datomic (68)
- # devcards (4)
- # docs (27)
- # duct (67)
- # emacs (15)
- # events (1)
- # fulcro (8)
- # graphql (50)
- # lein-figwheel (1)
- # lumo (15)
- # numerical-computing (1)
- # off-topic (77)
- # om (3)
- # onyx (5)
- # parinfer (3)
- # planck (2)
- # portkey (5)
- # re-frame (4)
- # reagent (16)
- # ring (14)
- # rum (3)
- # shadow-cljs (17)
- # vim (1)
my strategy for finding the relevant node in part b was:
* (ab)use tree-seq
recursively to get a list of every nodes "tallied" weight - the weight it holds
* group-by
parent
* filter for unbalanced groupings
* get the one with the lowest tally (will be deepest in the tree)
part 1 was simply "the node which supports, but isn't supported" -- i.e. (first (filter set-of-supportees supporters))
hmm tokyo timezone is good for getting the new questions when they come out, but not so great for discussion 😕
I was inspired to write my first macro.. it's a let which you can drop *stop*
into and it will throw an exception with the bindings up until that point as data
https://gist.github.com/minikomi/b6e5a097970513934faf46f01f194725
when solving these problems I often have a long let
within a function which somehow goes wrong..
what kinds of stuff did you have?
It was basically a way to write functions that could be partially applied at fixed points
https://github.com/armstnp/advent-of-code-2016/blob/master/src/advent_of_code_2016/day8.clj#L45-L49
ah, I see
So I can bind the parts of the operation I know at read-time, and then hand it the remaining context at execute-time
this is both the blessing and curse of Lisps
you can make your own syntax!
you can make your own syntax...
(well, not syntax per se)
In these cases, I found it easier than having to let-bind around an anonymous function
oh sure
one problem that I have is that, since I don't use clojure that much, I'm not savvy to all the clever things that I could do with builtins, so I worry that I sometimes rebuild things that already exist
for example, I don't know if Clojure has any partial application support short of reader function literals
Def. poke around the solutions here, you'll learn a lot of new functions that way, and how they're commonly (and sometimes uncommonly) leveraged. 4clojure used to be great for that, but I think it's down nowadays...
Partly because for small arities, it's just quicker to use #(f bound-param %1 %2)
, or something like
I'll stick that one in my toolbox
but now I think it's bed time
take care
It may be repetitive, but I really do end up getting into these micro-interpreter type problems >_>
hah, I had heard in passing about reductions
but didn’t know it’s called that. I searched for scan
, didn’t find it so wrote my own
When a lot of these problems move from 'find the answer' to 'tell me something about the state along the way', reductions usually shows up
not a fan of the first element behavior though
(reductions str [1 2 3])
=> (1 "12" "123")
No, yeah. Reduce always takes the first element as it stands if you don't provide a default
well, there’s always (drop 1)
lazy evaluation
@mikelis.vindavs that's maybe a little much only an hour after it dropped
good point
I kind of assumed this is a spoiler-alert zone
Yeah, I know what you mean. I'd give it at least another couple of hours. Or perhaps just point people to your repo. Then they know what they're in for.
it’s just general bikeshedding, I should probably get to work instead 😅
I was trying to save lines by trusting input https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day8.clj#L15-L24
Nice. I like how you documented the lines. I've been getting lazier as the days have been getting on. I'll clean it up in the morning. Time for sleep for me.
you mean with ->>
inside of ->
?
it’s neat, I only wish it worked the other way. the workaround there is to create a lambda
(->> {}
(#(assoc % :x :y)))
I never know what to use for the name
that’s a good choice, stands out.
I’m loving this channel and the community so far!
as->
is new to me! Much nicer to pick up than the magic wand / swiss arrows for most things, I bet
Today was ok. I found the answer for part 2 while trying to find part 1 it turned out 😉. 5 ms performance.
Posted my solutions to day 8. Highlights: cond->
, case
, reductions
. https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day08.clj
@borkdude I find it intriguing that you used clojure.core/==
instead of clojure.core/=
, what's the rationale?
@minikomi I had that too, but figured that when I would run someone elses input, bad things may happen on my machine: https://github.com/borkdude/aoc2017/commit/113de2ba459997544a6376a9944db41472d75bd6
@val_waeselynck mapcat vals
- good one
I noticed most people don't initialize the registers to 0, but this could lead to subtle bugs if all the registers that were updated end up being negative, and some of them are untouched you may end up with the wrong result (the right result being 0
).
mine for today: https://github.com/skazhy/advent/blob/master/src/advent/2017/day8.clj Curious to see if anyone tried the creative approach of transforming the whole input to s-expressions & then evaling it.
Yes, I used eval
@karlis. It even works in self-hosted ClojureScript 🙂 https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_08.cljc#L22
I didn't generate an entire namespace from the source input, if that's what you mean. 😀
Solution in PostgreSQL: https://twitter.com/pg_xocolatl/status/939099677026340864
@karlis Someone seems to have done this in Python: https://www.reddit.com/r/adventofcode/comments/7icnff/2017_day_8_solutions/dqxuwrz/
https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day08.clj
@bhauman for fn-map I had: (defn op [sym] (get {’!= not= ’inc + ’dec -} sym (resolve sym)))
My solutions are up. I used eval
FWIW: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_08.cljc
Here’s mine - I had failed to cope with eval in the past due to the lack of access to the lexical context, so I just went with a plain reduce. https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day8.clj
I could definately golf it some more, avoid repeating solve1 code in solve2 and replace the loops with reduce 😄
It seems a lot of people are using read-string
for these, then destructuring the resulting vector… You wouldn’t usually do that, would you? Given the docs’ warning that read-string can eval code?
@orestis If I'm reading your code correctly, you can write
(update context target #(op (or % 0) am))
as
(update context target (fnil op 0) am)
Yep, I saw fnil
in @nooga’s code and thought the same — I’ve yet to finish my 3rd read-through of clojure.core
😉
@orestis Yeah, in real code I would parse things and not use read
or eval
. But this is AoC, one of the few places you can 🙂
@orestis Hey, even using (or x y)
to deal with falsey x
is a non-intuitive idiom that you learn to use after starting the journey 🙂
It’s a bummer that get
offers a default value but update
doesn’t. Breaks the symmetry.
To be honest, I think the most profitable way I learned things is by reading other's code
my dirty secret is that despite writing almost exclusively clj and cljs for the past 3 years, I still look at ClojureDocs every 5 minutes
I'm proud to have what I suspect is the slowest solution for day 8, coming in at 5 seconds
I think it’s because I don’t pay close attention to simple things like argument lists when focusing at the problem I’m currently solving
but often you will be thinking “huh, does re
in clojure.string/split
have to be re or can it be a string”
I would love if Dash could look up clojuredocs. I wonder if there’s a plugin for that.
hm, as we figured out, it’s impossible to compare the performance unless we run each other’s code
Today should be roughly comparable for everyone, assuming everyone has 1000 ops to run, there’s no loops or any other funky stuff going on there.
I have to clarify; 5ms is what time
prints when running within CIDER. Not sure if the JVM is hot/cold/lukewarm/whatever.
Both parts run in 5 ms for me (with criterium), but that’s because the first run already contained the solution for part 2
@mfikes I like the use of spec to parse the values. I should start using that instead of regexes.
for now read-string + destructuring is my favorite way, although spec sounds more interesting 🙂
I haven’t encountered a nil pointer with max… I think the behavior of (max) is undefined, like 1 / 0
`(defn maximum [& args] (when-let [args (not-empty (filter some? args))] (apply max args))) `
If you use reductions
in the second part, and you don’t use a pre-populated map, the first few steps will give you an empty map until the first successful operation.
Cool mapcat
solution. Perhaps (concat [1 2] nil [3 4])
’s nil
-punning should be in its docstring
@cjmurphy you could initialize kept-highest to 0, because this was the initial value of all registers
kept-highest
is the 'running maximum' for part two, so not actually a register value.
@cjmurphy yeah, that’s why you could seed the running max with 0, because that’s the initial max
@orestis Right. I also discovered (merge-with + [1] {0 2})
accidentally works, but I suspect the concat
behavior is intended. Hrm.
@cjmurphy I did it this way: https://github.com/borkdude/aoc2017/blob/master/src/day8.clj#L54
I intitialized kept-highest/cur-max
to Long/MIN_VALUE
and now no more nil
problems with max
. So good point that there should not be problems with nil with max in the first place.
There would be a problem with 0
if all the register values were negative, and were always being set to negative.
Sure so no problem using either 🙂 I just like using the min possible value as the default for finding the maximum.
(If you have to use a default - if there really were none then nil would be better of course).
If there really is no input you want the running maximum to end up at nil
. So I settled with @bhauman's function that avoids both the arity exception and the NPE, with no default (i.e. nil default) for the running maximum in my code. Repeating his useful function here:
(defn maximum [& args]
(when-let [args (not-empty (filter some? args))]
(apply max args)))
If however you did use a default value, and you interpreted 'the highest value held in any register during this process' to exclude registers that are only ever read from, and also to exclude the from value of registers that are set, then it would be possible for the 'running maximum' to end up as negative, in which case Long/MIN_VALUE
will result in a correct outcome as long as there are a positive number of registers set.
If you attach any likelihood to the definition of 'held' requiring write then zero is not a good default. If you attach any likelihood to there being zero length input then it is better not to have a default at all. Good to be liberal with what you accept.
@cjmurphy the invariant is that held is the maximum of the previous state. 0 is exactly that.
I just thought that it was possible that held means read and write. Very woolly word 'held'.
Actually, I don’t really see a good solution to this whole mess given what Val pointed out. It seems you really need to initialize all your registers to 0. (Unless there is a way to accommodate not doing that.)
as registers aren't really defined before hand, the only case is where you have a register for a predicate value that isn't ever used
That register wound’t appear in your lazily-produced map, but has a theoretical value of 0
Finally, a reason to have used Spec to parse!
(s/exercise ::instr 4)
([() []] [() []] [() []] [(?? MN -2 if *o -t/LR 1) [{:tgt ??, :upd MN, :val -2, :if if, :lhs *o, :cmp -t/LR, :rhs 1}]])
One immediate bug this would ferret out for me is I have no function named MN
. I would need to revise my s/def
or do something.
For generating register names: https://github.com/borkdude/aoc2015_day7/blob/master/day7.clj#L11
Yes. This is perhaps another argument to use Spec over hand-rolled regex’s: You can more succinctly define valid input: https://github.com/mfikes/advent-of-code/commit/84774e390f5ea82568cf1c87308b125692611a0e#diff-ae7d8fc250d870104fa0c68af9f2e19a
In PureScript I’m expecting an ADT for these things, although you could also just do it with a set there
eval is not evil: https://github.com/ChrisBlom/advent-of-code/blob/master/src/adventofcode/2017/day08.clj#L20-L32
@chrisblom Bravo! That's an extremely consumable solution, IMHO. By the way, I used eval
as well. I also checked your solution and it works in Planck.