This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-11-26
Channels
- # adventofcode (2)
- # announcements (9)
- # bangalore-clj (1)
- # beginners (158)
- # calva (32)
- # cider (2)
- # clara (4)
- # cljdoc (40)
- # cljs-dev (3)
- # cljsrn (6)
- # clojure (45)
- # clojure-brasil (2)
- # clojure-dev (35)
- # clojure-europe (9)
- # clojure-italy (7)
- # clojure-nl (2)
- # clojure-uk (29)
- # clojurescript (144)
- # code-reviews (3)
- # core-logic (9)
- # cursive (11)
- # datascript (8)
- # datomic (9)
- # duct (1)
- # figwheel (6)
- # fulcro (11)
- # hyperfiddle (27)
- # kaocha (23)
- # luminus (1)
- # off-topic (7)
- # onyx (2)
- # pathom (3)
- # re-frame (61)
- # reagent (12)
- # remote-jobs (10)
- # shadow-cljs (40)
- # spacemacs (4)
- # sql (27)
- # tools-deps (6)
- # unrepl (3)
- # vim (47)
Thanks @andy.fingerhut! (flush)
did the trick
Hey All. When I do (map (fn [nr] '(nr)) [1 2 3])
, the result I get from my REPL is ((nr) (nr) (nr))
, why isn’t this ((1) (2) (3))
?
A pedantic correction. quote
isn't recursive. Recursion implies it looks inside the data structure. It's evaluation semantics are simply, return the thing.
oh wow yeah that works, I don’t understand exactly why though. Is the quote character somehow telling the compiler to take everything inside of it literally?
it would be more accurate to say that quote stops the compiler from doing half of its job. Normally, it “reads” (from characters into Clojure data structures), then “evaluates”. Quote says to not evaluate and just return literally the data structures that were read.
precisely! when you see quote, everything inside whatever you’ve quoted will be returned exactly as it looks
@tim.degroote yes, the quote
special form (which '
maps to), tells the compiler to stop evaluation for the next form
there is also the syntax-quote form (the backtick), which accepts "unquoting" via ~
and "unquote splicing" via ~@
this is rougly equivalent to ['a 'b c 'd]
(except syntax-quote also namespace qualifies symbols)
oooh interesting, didn’t know this! This cleared it up for me, thanks a lot for the help @schmee @bronsa!
you can read a bit more about syntax-quote here https://clojure.org/reference/reader#syntax-quote
Is there something like resolve
that, rather than returning the var, returns the fully qualified symbol name?
hmm. no not quite right. (comp resolve symbol) returns a var again. I need the fully qualified symbol
((comp symbol resolve) '+) ClassCastException clojure.lang.Var cannot be cast to java.lang.String clojure.core/symbol (core.clj:579)
if you're on 1.9 you'll have to do it manually by accessing the .sym
and .ns
fields of the var
Hello guys! I’m writing a small program that solves n-puzzle problem with a* algorithm. The main function iterates over different states of the puzzle to find a path towards the goal state. I used atoms to hold some local state in the function and it worked just fine, but I feel maybe there is a better (more performant or idiomatic) way to do it. I understood that atoms are used for synchronous concurrent state. In my case I don’t have any concurrency involved. I’ve been thinking maybe :^dynamic
vars with binding
and set!
can be a solution. Here is the code:
(defn solve [pzl heur]
(let [target (generate (count pzl))
a*-eval (partial puzzle/a*-eval heur)
open-set (atom (priority-map pzl (a*-eval pzl)))
closed-set (atom #{})]
(loop [cur (first (peek @open-set))]
(swap! open-set pop)
(swap! closed-set conj cur)
(if (not= cur target)
(do
(doseq [neighbor (get-neighbors cur)]
(let [neighbor-cost (a*-eval neighbor)]
(when-let [neighbor-cost-in-open-set (@open-set neighbor)]
(when (< neighbor-cost neighbor-cost-in-open-set)
(swap! open-set dissoc neighbor)))
(when-let [neighbor-in-closed-set (@closed-set neighbor)]
(when (< (puzzle/count-parents neighbor)
(puzzle/count-parents neighbor-in-closed-set))
(swap! closed-set dissoc neighbor)))
(when-not (or (contains? @open-set neighbor)
(contains? @closed-set neighbor))
(swap! open-set assoc neighbor neighbor-cost))))
(recur (first (peek @open-set))))
cur))))
Maybe, somebody can give an advice?why are you using atoms?
to change value of the queue and closed set. I didn’t take much time to come up with a recursive algorithm
you are paying a perf overhead for using atoms where there's no data races, and the idiomatic version would be to return new values for open-set and closed-set from each step that can alter them
including making open-set and closed-set args to the loop/recur
also, in code that actually used the atoms for concurrency, your usage of the atoms would have a race condition
ok got it, I would reformulate the code. can you briefly describe the last point?
(let [foo (peek @a)] (swap! foo pop)) - this is a race condition because the two usages of foo to peek and pop are not coordinated
two blocks could peek the same value, and then pop two different values
thus using one value twice, and dropping another value on the floor
basically any pair of operations on the same atom that mix a read and a write are probably a race
got it, thank you a lot!
in your case the race never happens because the code is known to be single threaded
but it's good to recognize patterns like that
absolutely, I’ve been thinking how to parallelize the algorithm to get better performance, but that maybe the next step after refactoring to recursion
the pattern you'll likely end up with: (let [[open-set closed-set] (op open-set closed-set) [open-set closed-set] (op2 open-set closed-set) ...] [open-set closed-set])
it becomes simpler if you group the data that gets changed together into one map with keys for each valaue
so (-> {:open open-set :closed closed-set} (op) (op2) ...)
then you rewrite each of the nested conditional ops into separate functions you can place into that chain
thanks a lot!
the conceptual approach is changing each "thing" that changes some object into a function that takes the object and returns a replacement
this is part of why vectors and maps are so ubiquitous in our code - we need to keep track of multiple updated values if a function needs to update more than one piece of data
Hello there, i have a short question. Do I understand it correct that if i use cond
all expressions are evaluated?
(cond (do (prn "eval test 1") false) (prn "result 1")
(do (prn "eval test 2") true) (prn "result 2"))
should be able to show you what is going onnote which tests are evaluated and which consequences. change up true and false as well
Ok thank you very much! I was confused, because i thought it would always evaluate all expressions 😆
Heya, my google fu is failing me, lets say I have a core async channel with collections of values, is there a simple function to put those values one-by-one on that channel?
so, visually I have something like this: ... -> [a b c] -> [d e f] -> [g h i] -> ...
, and I want to go to ... -> a -> b -> c ... -> g -> h -> i -> ...
you could use a (mapcat identity)
transducer on the channel
or actually maybe just cat
can’t say I’ve ever done that but might be just right
yeah, I was googling for transducers but couldn’t wrap my head around how that would work ‘the other way around’ so to say. Will try, thanks!
yeah, that should work fine
(def c (chan 100 cat))
Cool, thanks for verifying
oh huh how does that work with buffers
there's also onto-chan
that you can read the docstring of to see if it helps here or in other similar situations
core.async is a … bit to get my head around haha
Feeling a bit like a plumber, “does this channel fit to this channel”
I am writing a spec for a tuple
. The only condition is that both positions in the tuple have to be the same data type. For example,
[1 45] ; good
["hello" "blah"] ; good
[:hello :blah ] ; good
[1 :hello] ; bad
How would I go about doing this?a spec is a predicate, so can you write a predicate that given some data returns true if it matches your criteria and false otherwise?
to ensure same type, you’ll need some custom predicate
but you can either write your own or combine with something like s/tuple or s/coll-of
troubleshooting figwheel hanging on compile?
(print-config id ...) ;; prints out build configurations
(fig-status) ;; displays current state of system
(figwheel.client/set-autoload false) ;; will turn autoloading off
(figwheel.client/set-repl-pprint false) ;; will turn pretty printing off
Switch REPL build focus:
:cljs/quit ;; allows you to switch REPL to another build
Docs: (doc function-name-here)
Exit: :cljs/quit
Results: Stored in vars *1, *2, *3, *e holds last exception object
Prompt will show when Figwheel connects to your application
[Rebel readline] Type :repl/help for online help info
... never goes anywhere
i even started a fresh project via lein new macchiato app
;_;
vas$ cat profiles.clj
{:user {:plugins [
[lein-ancient "0.6.10"]
[http-kit/lein-template "1.0.0-SNAPSHOT"]
]}}
do i need figwheel in my plugins? o.o
Thank you
for now I try with commenting out lein-template and see how it goes.
strangely, my app was compiling yesterday. so i don't know what i changed that caused it to no longer function. and there's no errors... so yeah, probably something weird in the dependency chain
hey that may be so, but i can use cljs and make a node server so... it's nice [when working]
no i don't even know what rebel readline is
i think that was there yesterday, that helps color code the repl iirc
and i had color coding so
thanks. i may try disabling it... it's not actually getting me to a repl
the last time I did any cljs stuff I wrote a little script that called the cljs compiler and generated some js from some cljs code, which node was pretty happy with, without all that stuff
you're saying maybe do it from scratch without macchiato?
yeah. i could just make an empty figwheel project using rum that also compiles a javascript file for a node server...
i can't start the node process until the javascript is compiled, and that step never completes.
i really don't know what i did, but it just hangs on compilation
hangs on launching CLJS repl
i guess the JS is compiled... lemme try firing up that npm process
doh! @lilactown launching the npm process was the answer!
^_^ thank you
wishing i hadn't undone about ~2 hours of commits eaarlier but heyyy live and learn
Hey everyone, how can I get some useful information from errors thrown during tests run by shadow-cljs using cljs.test? For the following:
(deftest test-nonsense
(doall (map identity identity)))
I get:
ERROR in (test-nonsense) (Error:NaN:NaN)
Uncaught exception, not in assertion.
expected: nil
actual: #object[Error Error: function cljs$core$identity(x){
return x;
} is not ISeqable]
I've tried file-and-line
but it gives me nil for both.if you're using sourcemaps you can get node to leverage them in stacktraces via https://nodejs.org/en/docs/guides/debugging-getting-started/ - it should also wor kfrom chrome devtools if you're using it as a client when using node --inspect
or --inspect-brk
you're probably having shadow-cljs auto-run the tests, but you can also run them from a terminal using node <output/location/of/tests>.js
Yep, I am autorunning. I'd like to keep that, although I am fiddling with the manual running for now
Is there no way to get better traces without using a debugger though? I've never been super happy with js errors, but I know there are stack traces to be had
I just tried running the bad code outside deftest
and got a lot more information. Is there a way to get cljs.test to not suppress the stack?
you'll need the sourcemaps - you should be able to just add that node module I linked as a dep or dev-dep and just require it at the entrypoint to the code. having not used shadow-cljs, I don't know how that would differ from the regular compilation wrt :npm-deps
running the offending code in a REPL is always a good idea. easier to hack on it, anyway
@U9QQRN612 which node module? You linked to a docs page about more general debugging.
as for customziing output from cljs.test... I know there are some general variables for customizing error behavior, but the only one I know offhand is *print-err-fn*
FWIW, I figured out where I was having trouble. In the repl or when running my code, errors were formatted as expected, using source maps; in tests, however, errors are caught by cljs.test and formatted using the :formatter
property of the test environment, which you can pass to run-all-tests
. I added a main
function to my testing shadow-cljs build with a custom error formatter that invokes *print-err-fn*
if it's an error. Here's my code:
(defn print-err [e]
(if (.-stack e) (*print-err-fn* e) (pr-str e)))
(defn main []
(run-all-tests #"my-project.*" (assoc (test/empty-env) :formatter print-err)))
vectors don't have a fast way to insert in to the middle, so you should avoid doing so
If it helps, I’m inserting a map if there is none into a hiccup vector which I believe has a maximum number of 3 elements.
My approach would be (defn insert-v [v idx value] (into (conj (subvec v 0 idx) value) (subvec v idx)))
but inserting in the middle is still going to be O(n)
@U0NCTKEV8 is the problem with flatten that there might be sub-collections?
core.rrb-vector ( https://github.com/clojure/core.rrb-vector ) also has a catvec
which will still work efficiently by converting regular vectors but I believe there is still some question as to whether it has (performance) edge cases
FWIW, I figured out where I was having trouble. In the repl or when running my code, errors were formatted as expected, using source maps; in tests, however, errors are caught by cljs.test and formatted using the :formatter
property of the test environment, which you can pass to run-all-tests
. I added a main
function to my testing shadow-cljs build with a custom error formatter that invokes *print-err-fn*
if it's an error. Here's my code:
(defn print-err [e]
(if (.-stack e) (*print-err-fn* e) (pr-str e)))
(defn main []
(run-all-tests #"my-project.*" (assoc (test/empty-env) :formatter print-err)))