This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-05-03
Channels
- # beginners (111)
- # boot (1)
- # braveandtrue (4)
- # calva (2)
- # cider (16)
- # clara (35)
- # cljdoc (4)
- # cljs-dev (22)
- # clojure (80)
- # clojure-dev (17)
- # clojure-europe (3)
- # clojure-italy (57)
- # clojure-japan (1)
- # clojure-nl (4)
- # clojure-serbia (1)
- # clojure-spec (25)
- # clojure-uk (108)
- # clojurescript (67)
- # cursive (17)
- # data-science (5)
- # datascript (6)
- # datomic (6)
- # devcards (1)
- # events (1)
- # expound (13)
- # figwheel (2)
- # figwheel-main (6)
- # fulcro (7)
- # jobs-discuss (8)
- # kaocha (1)
- # luminus (3)
- # nrepl (6)
- # off-topic (58)
- # re-frame (1)
- # reitit (16)
- # remote-jobs (1)
- # ring (1)
- # shadow-cljs (70)
- # spacemacs (10)
- # sql (42)
- # testing (1)
- # tools-deps (8)
- # vim (1)
What is this form of function body called:
(defn my-fn [args]
{value (<body>)
other-value (<body>)})
googling has not helped me find this šThat's just a function that returns a map, there's not really a special name for it.
Yes, if you're used to languages that use an explicit return
statement to return a value, it can be surprising.
Here's a function that returns the number 42:
(defn answer-to-life []
42)
You have to have something after the square brackets, even if it's only nil
, but other than that you can put any valid Clojure expression.
Whoa, son of a gun, it is!
Ah well, I've only been using Clojure since version 1.2, can't expect me to know everything yet š
tbh I was debugging someone else's code (2nd month of a FT clojure job as a somewhat clojure newbie) and there's actually a bug in how this fn is called so I was like "is there some special form here I'm missing?" --- haha... no, it's just a map...
Question: If I did count
on a large, lazy sequence, it will release it's references to the elements as it goes along (guess I'm assuming that there are lazy sequences such that an O(1)
shortcut isn't possible). That is...it's not going to try to keep a huge sequence in memory? I guess I can try to crash and find out...but maybe somebody has something relevant to add
You can try (count (range))
and the operation will timeout. (range)
returns an infinite sequence.
Got it, so the answer is "yes, it will hold the whole or much in memory" ? Otherwise, it seems like it would just hang on the above as the garbage collector furiously cleans up
I believe it would hold the entire thing in memory.
I'm not sure I ctrl+c'd after a minute
I would see if it goes OOM
I think once you realize the entirety of a lazy-sequence then it becomes non-lazy. Otherwise it will cache the realized results, and hold off on the rest. So when you try to realize the entirety of range it will try to hold it all in memory. (Someone correct me if I'm wrong)
@christian.gonzalez @mkeller02 it will eagerly realize all the elements, but will not hold them in memory
they will be held in memory if some other binding holds onto the head though
(count (range))
doesn't OOM, eventually it gets a numeric exception iirc
(though if it kept going with bignums instead of overflowing the numeric type, eventually you'd produce a number too big to fit in memory...)
@christian.gonzalez realizing a lazy data type doesn't make it non-lazy, it just makes it fully realized
it always caches elements that are realized, but the gc can drop them anyway if there is no path to them via live objects
though if you retain the head, the path is still there right
I think something like doall
will walk the lazy sequence, realize it, retain the head, and make it non-lazy
doall does not retain the head or make it non-lazy
doall is all you need. Just because the seq has type LazySeq doesn't mean it has pending evaluation. Lazy seqs cache their results, so all you need to do is walk the lazy seq once (as doall does) in order to force it all, and thus render it non-lazy. seq does not force the entire collection to be evaluated.
https://stackoverflow.com/questions/1641626/how-to-convert-lazy-sequence-to-non-lazy-in-clojure
Per the docstrings it mentions that doall
retains the head and returns it.I don't work too often with lazy-seqs so I'm just trying to wrap my head around it
a forced lazy-seq is still a lazy object - it's just one that has been realized
this is more than just a pedantic point because eg. the toString of things that are lazy is annoying and unuseful, and doall doesn't help with that
(ins)user=> (str (map inc [1]))
"clojure.lang.LazySeq@21"
(ins)user=> (str (doall (map inc [1])))
"clojure.lang.LazySeq@21"
actually making it non-lazy (a different type)
(ins)user=> (str (vec (map inc [1])))
"[2]"
ah that makes sense, still a lazy sequence in the end
right, LazySeq is a specific class in the vm, and the return value of doall is still an instance of that class
idk if this is a high quality post, but it seems to touch on relevant questions http://programming-puzzler.blogspot.com/2009/01/laziness-in-clojure-traps-workarounds.html
the tldr seems to be if you have a named reference to your lazy sequence, clojure caches it as it goes. but if it's anonymous, the GC cleans up as it goes
@dougkrieger that's almost it, but clojure is smart about closed-over things that can be cleaned up as well
(let [r (range)] (count r))
- clojure knows that nobody can access r after count starts, and allows its items to be gc'd
this is part of why normal debugging of clojure is hard - you actually have to turn the behavior off to make a normal debugger work
"locals clearing"
I wasn't sure if it auto-promoted
@dpsutton you won't get longrange unless you specify an "end" arg that is a long, and... that precludes that kind of error I think
aha, the case where you provide no args just uses inc'
- so you'd eventually run out of room for the number, yeah
count returns an int, so a long range with a size larger then can fit in an int will have some kind of error too
is there a hof in core like "once" that takes a function and will only run it once no matter how many times it's called?
there's memoize
, which calls your function once per unique arg-list
there's also delay, which is defined in terms of a single block of code that is only evaluated once, but not until it's asked for
I have an atom that I want to occasionally redefine initial state, and constantly changing between "def" and "defonce" is annoying. I'm not sure wrapping/unwrapping in memoize would be better
if that's the usage, why not a defonce plus a function that assigns its initial state via reset!
that's actually what I'm doing right now, so what I'm really considering is wrapping reset! in memoize and removing memoize when I want to change state
I could just comment out the reset call at the risk of forgetting what I did and messing up production bundles
why not put the reset! in a function that isn't called at the top level?
(except maybe inside the defonce...)
(defn reset-foo [a] ...)
(defonce state (doto (atom {}) reset-foo))
then you can easily use it later manually, but it only runs implicitly once
hmm, maybe slurp/vomit is the editor mechanic I need to make this smoother. I could do as you just defined, then vomit the reset-foo call out when I want to revert/change initial state
if it's done like above, you don't need to edit the code (beyond changing how reset works of course)- just call reset-foo by hand (redefining as needed) from the repl
the general pattern is to use functions to abstract unconditional side effects into functions so a repl user can decide when they run
(you can do similar with -main to avoid running vm shutdown stuff in the repl etc.)
in fact, I'd usually prefer to do the state-init inside -main rather than at the top level
I wire up state before main. I suppose I could wrap all of that logic inside a function definition though and call that within main
it's easier to use the repl if you don't complect namespace loading with state initialization (to use one of RH's favorite words)
i.e. have the top level only execute namespace loading, pure function definitions, and call to main?
well, the top level shouldn't even call main, but yeah
and then anything interesting that main does should be in functions you can call selectively
is the benefit there to enforce this sort of contract that any top-level form (aside from main) can be run in the repl with no side effects?
yeah, that's pretty much the idea, there's libraries designed to make this easier to implement (stuartsierra/component, integrant, mount, etc.)
you end up with side effects all being defined inside the state object, so if you want to run without one of those side effects all you need is to replace that part of the state object
then the state object passes through (or needs to be manually passed to) any code that needs to invoke side effects
(side note: annoying that spacemacs doesn't have nice evil slurp bindings ootb *edit* jk it does)
When I run lein with-profile clj,dev test com.foo.bar-bar.automated-tests
I get Could not locate etaoin__init.class... on classpath.
but I've added [etaoin "0.3.3"]
to the dependencies... What else might be the issue?
usually using with-profile I want +foo,+bar
otherwise you need to explicitly provide all the profiles, even the ones that should be implicit for the task (eg test here)
I don't think it will look at test-paths if you don't provide a profile that wants it
Hello, Iām used to the cond
from Scheme, does the cond
in Clojure support the =>
syntax?
(answered in #clojure )