This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-02-15
Channels
- # adventofcode (13)
- # aleph (5)
- # announcements (8)
- # beginners (87)
- # calva (9)
- # cider (102)
- # cljs-dev (71)
- # cljsrn (2)
- # clojure (198)
- # clojure-dev (28)
- # clojure-europe (3)
- # clojure-italy (27)
- # clojure-nl (3)
- # clojure-spec (1)
- # clojure-uk (43)
- # clojurescript (121)
- # component (11)
- # cursive (20)
- # data-science (13)
- # datascript (2)
- # datomic (102)
- # dirac (4)
- # duct (5)
- # emacs (14)
- # figwheel-main (7)
- # fulcro (37)
- # hoplon (11)
- # jackdaw (3)
- # jobs (2)
- # leiningen (16)
- # nrepl (2)
- # off-topic (51)
- # pathom (34)
- # pedestal (12)
- # perun (10)
- # portkey (1)
- # re-frame (6)
- # reitit (1)
- # shadow-cljs (21)
- # spacemacs (8)
- # tools-deps (2)
- # vim (2)
3% said they were using something older than 1.8, but they could also have been using something newer
just as a datapoint, CIDER now requires a minimum of 1.8 to work. There are still a few cljx based projects out there that are in wide use. cemerick's url package and its dependency pathetic for example
@noisesmith, so if I switch to refs instead of atoms, it would be ok to use watches? I'm little bit reluctant to just use a function, as even getting derived lookup-index from data that stored in first atom requires to process over million rows, that's why I was thinking about caching it.
sounds like what you want is a cache, and then an atom used to derive the cached values, and clear of (parts of) the cache if the atom changes
you might want to check out core.cache, and for that usage a cache used by a function over an atom would make sense, where alterations to the atom might clear some or all of the function's cache
using two atoms together isn't generally doable in a correct way, but a cache of a function over an atom is doable
Trying some examples from SICP I've found that Ratio is pretty slow - is that expected? E.g. using continued fraction to compute inverse of golden ratio:
(defn cont-frac-iter [n d k]
(letfn [(frac-iter [i acc]
(if (< i 1)
acc
;; WARNING: if you don't use double coercion then the procedure will be slow for large k
(recur (dec i) (double (/ (n i) (+ (d i) acc))))))]
(frac-iter k 0)))
;; this is pretty fast
(time (double (cont-frac-iter (constantly 1)
(constantly 1)
100000)))
;; "Elapsed time: 14.10361 msecs"
;; => 0.6180339887498948
;; BUT!
;; Original version without doulbe coercion and k=5000 took more than 3 seconds!!!
;; "Elapsed time: 3642.036658 msecs"
;; => 0.6180339887498948
Clojure Ratio values are exact, and I believe that every single arithmetic operation you do on one also does a greatest common divisor calculation to reduce the numerator and denominator integer values to lowest terms, changing the type to an integer if the result happens to be one.
Because the results are exact, if the numerator and denominator get large, then all calculations will be doing exact arithmetic on large integers.
Folks, this strikes me as a question where I am sure that the answer is going to embarrass me, but I am drawing a mental blank. Is there a simple way to toggle a single item within a set. I.e. if it's there remove it, if not add it? Used to do this with set xor in my JS days.
Yeah, can definitely do that. I just had this, "I am sure there is an API function for this" feeling. If not it's good, means I am not going crazy đ.
I think the first example is probably the most readable barring the existence of a (toggle s i)
function or similar. I occasionally get this weird thing that happens in my brain where I think, "Ok, I am sure that there is either a built in function for this, or an obvious pattern that I am missing". No worries, thanks for your help.
Hah! That's a neat trick. I think this is the kind of thing I meant by some pattern that I might be missing. Will explore whether converting to a map makes sense. This is all "first world problems", the contains check is not that complex anyway really.
Is it possible to write docstring in defmethod
when using multimethod?
I have this weird problem, where I get a ClassCastException
when calling (class x)
but no error when calling (.getClass x)
. Here's the code:
(let [^Property src (get-prop inst)
[target-id target-prop] val
target-inst (tree-search/find-nearest-by-id inst (str target-id))
target-class (.getClass target-inst)
get-target-prop (get-property-fn target-class target-prop)
^ObservableValue target (get-target-prop target-inst)]
(println "Now binding" src "with" target)
(.bind src target))
This works, but when I replace (.getClass target-inst)
with (class target-inst)
I get: java.lang.Class cannot be cast to clojure.lang.IFn
. What's going on here?@wesley.hall Thanks a lot for your answer đ
Guess I am doing something wrong if I need to have docstring in the method xD
@neo2551 No worries. I actually quite often drop in a regular comment at the top of my multimethods in place of an actual docstring. Seems that I often find it useful to give a little explanation about what this specific case does. There is probably nothing to attach an actual docstring to though by the time all this stuff gets munged down to .class or .js.
So I have a test helper function that checks to see if a given string is in hashmap state
, which I use like (is (last-log-contains? state "Barrier"))
. This works fine when it's correct, but when it's not correct, the output is: expected: (is (last-log-contains? state "Barrier")) \n actual: (not (last-log-contains? [FULL STATE CONTENTS HERE] "Barrier"))
. Because of how this app works, the state
hashmap can occasionally be extremely massive, which is tough to handle in test output.
(defn last-log-contains?
[state content]
(some? (re-find (re-pattern content)
(-> @state :log last :text))))
Is there any better way to write the function to avoid this? Is there any better way to write the is
assertions to avoid this?
perhaps you could check (select-keys state ["Barrier"])
for the key rather than the full map. When you are wrong you will be presented only with the value of the thing you are checking
That's not a bad idea! Let me try that
And thank you @dpsutton and @bronsa! Your help yesterday was fundamental to me getting my PR up
or just feel better that you are doing things more correctly. that's always a win too đ
haha Mostly the last one. Compile times seem to take a bit longer, and the tests were already pretty quick, but this is a major win for DRY
We had 3 macros that did similar but slightly different things, and this allows me to extract the main let
bindings that were shared between the 3 into a single spot
You basically canât get back to that docstring at runtime. Itâs attached to the symbol foo*
.
You could also do something more drastic, like re-implement defmethod
:
(defmacro defmethod*
[multifn dispatch-val mymeta & fn-tail]
`(. ~(with-meta multifn {:tag 'clojure.lang.MultiFn})
addMethod
~dispatch-val
~(with-meta `(fn ~@fn-tail)
mymeta)))
However, itâs odd, because the docstring is attached to the function. Whereas the docstring of the multimethod is attached to the var.
there's a jira about this btw
So the unfortunate truth is, as @wesley.hall deduced, thereâs no consistent place to hang a methodâs metadata.
well, I thought there was, not seeing it now. I know I've had some conversation about it in the last 6 months
It doesn't seem like there is much point in supporting it because defmethods have no real identity. All of the tools that give power and usefulness to docstrings rely on being able to talk about a named thing, but defmethods are not named things.
Perhaps if things like the (doc)
function were changed to optionally support a dispatch value in the case of multimethods or something, but otherwise... why bother? đ
but yes, that's the tricky bit
I would say, in my case it would only be supporting docstrings in the usual "docstring location", even if they were ignored entirely at runtime, but all that is really for is consistency of documentation in the code itself.
It's not really a problem to drop in a standard comment, they just look different in cursive and I don't get the pretty green đ
Thanks a lot for all your answer!
(def valid-guid?
(s/with-gen
#(int? %)
(constantly 1)))
=> #'test-ns/valid-guid?
(s/form valid-guid?)
=> :clojure.spec.alpha/unknown
$ clj -A:test
Clojure 1.10.0
user=> (require '[clojure.spec.gen.alpha :as gen])
nil
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/def ::guid (s/with-gen int? #(gen/return 1)))
:user/guid
user=> (s/form ::guid)
clojure.core/int?
user=> (gen/generate (s/gen ::guid))
1
user=>
(def valid-guid?
(s/with-gen
int?
(constantly 1)))
=> #'test-nss/valid-guid?
(s/form valid-guid?)
=> clojure.core/int?
This is what I get:
user=> (s/form (s/spec #(int? %)))
(fn [%] (clojure.core/int? %))
Is there an existing pretty printing socket server repl I can utilize? Or do I need to write my own using clojure.pprint/pprint
, is clojure.pprint/pprint
even suited to pretty printing in a repl?
I'm happy to use fipp for dev, but I'm not so sure about production with fipp. I don't want to conflict with someone else's version of fipp.
Is it possible to check whether a given symbol corresponds to a protocol method?
e.g. (protocol-method? 'my-method) => true
, (protocol-method? 'inc) => false
@dominicm Fipp is very stable. It should be safe to just forcibly use the latest version.
if you ever have a problem w/ that, feel free to complain to me directly and iâll get a fixed build out
Is there ever a legitimate use of a map from keywords to functions instead of using a multimethod?
I suppose if the function to be called can change at runtime based on context. Meaning you have one keyword, but the fn associated with that can change.
If your multifn is just dispatching off of keywords, seems like mostly the same thing to me. You're just able to define your dispatch map across multiple namespaces and downstream projects.
@john yeah⌠basically, when dispatching on some function of an argument, a multimethod seems natural (or when there is a need for extensibility). But in my project I found myself passing a keyword as the first argument to my multimethod (a dispatch key) which is then totally ignored by the body of the function. It seems odd / a map would be cleaner
Yeah... IMO it would be cleaner, in some cases. The multifn approach is just so extensible - let's you build out that dispatch mechanism across namespaces.
np. Feel free to check out dispacio if you're looking for any more inspiration around dispatch strategies https://github.com/johnmn3/dispacio
The finest-grain control might be to plug in interceptors, for manually constructing dispatch strategies
Ah; Iâll definitely check this out! I had a similar question some time ago about using pattern matching v.s. multimethods; I think the answer is the same; it depends on how much you care about extensibility
Why do a lot of clojure functions on sequences return lists? e.g. (rest [1 2 3])
returns (2 3)
, forcing me to write (into [] (rest [1 2 3]))
to get a vector back. Am I doing something wrong?
FWIU, the list is the underlying data type of the seq
abstraction, which all functions that operate over sequences recognize.
If you are using rest for your computations things will be more efficient with linked lists (probably, by guestimate)
@hmaurer @john protocols are implemented as a map of names to functions
but special in having call-site optimizations
there's plenty of places where a map of "name" to function is a better simpler choice than a multimethod or protocol
Ah. Am I doing something wrong by assuming in my code that I have a vector? Because, say, if at some point in my code I assume that I have a vector and use conj
to append an element to the end, I now have to add into []
or similar to all sequence operations I do on that vector, to ensure it remains a vector
Thanks @alexmiller for the extra explanation on multi-methods
why do you need to ensure it remains a vector?
in practice, I'd say this is not a problem I ever have
hmm, maybe I am thinking of it as a problem but it wouldnât be in practice. Iâll try to ignore it and see
I would not do that
@emccue yeah, but I found myself bumping into it over and over and I thought that if the standard library behaves in that way then I might be doing something wrong
as you will then just build your own bespoke collection handling that is different than what is done everywhere else
since I doubt all clojure devs re-write those functions, otherwise they would be in the std lib
if you're having this issue, back up and explain how you got there
generally once I have sequences, I am never "conj"ing to them, I am manipulating them at the sequence level with sequence functions
it is usually a problem if you are trying write what is an imperative algorithm using arrays in clojure
I think you're maybe off down a side path from where hmaurer started
I rarely use conj directly
https://github.com/clojure/tools.deps.alpha is probably something visible I work on regularly. it has tons of data structures and data structure manipulation. I use conj twice in the whole code base.
or I should say, in two functions
Rarely does a clojure programmer not know obviously what the type being passed to conj is, I suppose. I rarely find myself getting bit by this either.
for example, if you where directly translating some javascript code, js allows you to call push or whatever (I guess an arraylist would be a better analogue to that in clojure) to push a value on to the front of an array
and basically all the clojure collection code is not built to support that style of usage
Well, I started like this. I have a map which I pass down some function, a âstepâ. This map contains a special key, e.g :remaining-steps [:a :b :c]
with the steps left to execute. What I do is I take that map, and run it through all those steps until that array is empty (so first :a
, look up the corresponding function, run it on the map, and keep going). Those functions can also push elements to the beginning of the vector under that key, adding more steps.
so if you were trying to use it like that, you would end up doing something silly like (into [] ...) everywhere
so it's a queue
I guess? I wasnât thinking of it that way. Itâs more like a bag of information that I run through a sequence of stages
basically like a middleware chain except that instead of directly calling the next one I add a keyword under a special key and some functions âaboveâ is in charge of calling them in order until there are no more to call
it's unclear from what you said whether you want a stack or a queue. if you want a stack, the fastest option is to use a list (and cons/peek/pop). You can also use a vector as a stack with insertion point at the end, but that's slower than a list.
(update amap :remaining-steps into :extra-step)
or conj
. But you already know it's a vector, so you know which direction conj works in in that case.
note that that syntax is cljs-only
clj has a queue, but not the literal for it, you just use clojure.lang.PersistentQueue/EMPTY to get an empty one
Folllow up question: is there a cleaner way to prepend a list of elements IN ORDER to a list than doing: (into some-list (reverse elements-to-prepend))
?
but what you are talking about is concat, the caveat with concat is becuase it builds lazy seqs if you are using it without care you will blow the stack when you go to realize it
one way to think of something like your remaining steps is as a program, and what you have is the simplest kind of program, a linear list of instructions
so you could support more complicated trees of instructions, so something like clojure's do
you have `[do-x do-y do-z] and some program (the abstract machine) takes do-x off the control stack and does it, possibly pushing other things on to the control stack
so you might have something like [[:do-2-things do-x do-y] do-z]
and have your abstract machine support do-2-things by pushing the 2 things back on to the control stack
Basically at first I was just piping something through functions with ->
, but I needed to add some machinery between every step, so I wrote this simple abstract machine because
when reloading a namespace with a defprotocol, Is there a way to avoid the dreaded IllegalArgumentException No implementation of method: :foo of protocol: #'com.example.foo/IFoo found for class: com.example.foo.FooRecord clojure.core/-cache-protocol-fn (core_deftype.clj:527)
by unloading the protocol somehow at the repl?
the readme for toolsnnamespace says âTo avoid this problem, always create new instances of records after a refresh.â which doesnât make sense to me, defprotocol is the thing that is throwing on reload
what they probably mean is that you need to refresh your instances of your FooRecord
, because if they keep surviving post refresh they refer to the old protocol
one way this can happen is if you def
them in a namespace, which you :refer :all
.
That said, I have very similar issues often, so there is definitely more going on
I asked about this problem in this channel a couple times very recently. no luck...
my conclusion (as suggested by someone else) is to resort to metadata-based protocol extension. I find the feature nifty anyway.
You can vary-meta
either defrecords ('thin' defrecords: implementing no protocols), or plain maps
if you support some kind of do
operation in your machine, and add continuations, you can process trees of instructions without having to do annoying concats of instruction sequences