This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-03-07
Channels
- # beginners (49)
- # boot (48)
- # cider (5)
- # cljs-dev (6)
- # clojure (165)
- # clojure-android (1)
- # clojure-austin (1)
- # clojure-india (2)
- # clojure-italy (23)
- # clojure-nl (2)
- # clojure-poland (4)
- # clojure-russia (63)
- # clojure-spec (5)
- # clojure-uk (121)
- # clojurescript (187)
- # core-async (1)
- # core-logic (4)
- # cursive (17)
- # datascript (1)
- # datomic (12)
- # emacs (2)
- # funcool (3)
- # hoplon (2)
- # jobs (7)
- # juxt (6)
- # lambdaisland (1)
- # luminus (2)
- # lumo (20)
- # midje (8)
- # off-topic (11)
- # om (38)
- # onyx (42)
- # pedestal (6)
- # planck (23)
- # protorepl (29)
- # ring (3)
- # rum (23)
- # spacemacs (6)
- # untangled (70)
- # vim (1)
I'm confused on how to compose recursive and iterative selectors in spector. If I want to select the 4th item in a depth first traversal of a vector represented by nested vectors so it's not this:
(select [(walker number?) (srange 3 4)] tree)
@arthur an example of what you're trying to do would be helpful
trying to get specter back in my head so i was working through the examples in your latest blog post
first off, I'd recommend using this instead of walker
:
(def TREE-VALUES
(recursive-path [] p
(if-path vector?
[ALL p]
STAY)))
walker
is very brute force and will descend into anything, like maps or lists that could be at the leaves
TREE-VALUES
is more precise and much more performant
then this: (select-any [(subselect TREE-VALUES) (nthpath 4)] tree)
OK, so I'm not understanding something about the way select works when given a vector of selectors and how it composes them. This is something I can work on 🙂 thanks
just think of it is navigating one step at a time
first it navigates to the sequence of elements found by TREE-VALUES
, then to index 4 of that sequence
subselect
is definitely a more advanced navigator
select
is an operation, subselect
creates a navigator
so every time I want to use the idea of selecting inside a call to transform or select i will use subselect ?
if it's important to navigate those elements as a single sequence, then yes
subselect
is very powerful but it's not needed that often in my experience
@nathanmarz What would a navigator that grabs values in an otherwise arbitrarily nested tree of vecs and maps look like? I originally did something with MAP-VALS but that doesn’t work as well for nested values of course 🙂
@lvh if you just want to descend into any data structure you can use walker
that will descend to map keys as well
otherwise you can be more precise by expanding on that TREE-VALUES
navigator I pasted above
(using cond-path
)
Sorry; I just realized I omitted an important bit: leaf values — but I guess the answer there is TREE-VALUES as well?
that definition of TREE-VALUES
is only for a tree represented with nested vectors
(cond-path vector? [ALL p] map? [MAP-VALS p] STAY STAY)
would descend into all vectors and into all map values
@nathanmarz Thanks! Why does STAY STAY
work at the end? I was expecting a predicate; maybe (constantly true).
@lvh conditions in specter are true if the given path selects anything
STAY
is guaranteed to select something (and is also the most efficient), so it's the best choice for the equivalent of :else
And STAY always selects. Makes sense. But (constantly true)
would’ve worked fine too then I presume?
yea that would work too
Is there a short hand for
(swap! some-atom
#(-> %
(update-in [ ... ])
(update-in [ ...])))
Cursors are your friend @qqq
Take a look at reagent.core/cursor
@fernandohur: what? reagent as in react layer reagent?
🙈 woeps, wrong channel. I though I was in #reagent for a sec
I have two functions that do different things, but have similar let bindings. Like (def foo [args] (let [similar-bindings-using-args] …))
and (def bar [args] (let [similar-bindings-using-args] …))
. Is there a way to share those bindings between them?
@negaduck : based on the bindings, you can turn the "args" into a map; then in both functions, you can use {:keys [ .. ] }
I was just going to write the same thing. Extract the common bindings into a function that returns a map.
@qqq I don't know of a shorthand for that, but I would like to know as well. I end up updating a map multiple times in an atom pretty often.
@jstew: it's possible I may go datascript for htis; it's getting dangerously close to the point where I just want to do db transactions for multiple updates
more seriously from the mouth of one of cassaforte's autors, cassaforte is not really developed anymore, alia is
@qqq shameless plug: check out the supdate library https://www.github.com/vvvvalvalval/supdate
Seems that way, couldn't get their "Getting Started" guide to work ("no matching ctor" error) and GH, Clojars & their Guide all disagreed on the most recent version 😉
I'm a happy alia user, and just last week moved my project to spandex (ES client from mpenet). Pretty happy with it. No issues.
I have a function which client code passes a zero-arg function to. I'd like to extend it to give the client's function some information, if it accepts it, but not break backwards compatibility.
you might be able to attach metadata to it, but yeah, if you need more information than 'is a ifn?" you probably want to use protocols
Protocols are often better for higher-order-programming anyways since functions become a bit less opaque about what they are accepting.
@peeja not the prettiest way, but might do what you need:
boot.user=> (defn f1 [f2]
(try (f2 42)
(catch clojure.lang.ArityException ae
(throw (RuntimeException. "f2 should be a function that takes X arguments" ae)))))
boot.user=> (defn f2 [n] {:answer n})
boot.user=> (defn f3 [] {:answer 42})
boot.user=> (f1 f2)
{:answer 42}
boot.user=> (f1 f3)
clojure.lang.ArityException: Wrong number of args (1) passed to: user/f3
java.lang.RuntimeException: f2 should be a function that takes X arguments
sure...and then call that on
😉
oh nvm, I see
you're adding metadata....but wait, doesn't clojure already do this?
Yeah, Clojure already does that @tolitius
Well it depends what you're trying to do I guess, Clojure already gives you the name and the number of functions you passed it
I guess your code would need to be expanded to do what @peeja was asking?
right, and there's no way to do that
I'm not sure how your code helps
right, so in order to still accept a wrong arity function and to have a legible error sent back he can wrap the exception
But that does require knowing ahead of time what the arity of the function was
In your code you have to know what "X" is somehow
right, so this is just a different way of attacking the problem. This code doesn't tell you what the arity is, it just gives you a better message when you get it wrong, providing you know ahead of time what the arity should be.
> I'd like to extend it to give the client's function some information, if it accepts it, but not break backwards compatibility
this is not a good solution to design, but as a temp fix until you get to use protocols, it'll do
@peeja yea, definitely not to control the flow, but since there is no way to figure out the arity at runtime, you should at least know when it is wrong
Does extend-protocol
guarantee order when used with subtypes?
E.g. suppose class Foo
implements interface IFoo
. Then, extending both Foo
and IFoo
with protocol Bar
:
(extend-protocol Bar
Foo
(do-bar []
"Foo-bar")
IFoo
(do-bar []
"IFoo-bar"))
Is calling do-bar
on an object of type Foo
guaranteed to give ”Foo-bar"
instead of ”IFoo-bar"
?some people have asked for a prefer-method kind of thing, but rich has pushed back (I forget the reasoning)
if it's not written down I'd say it's an implementation detail. probably work for a specific version of clojure but might change between versions
That’s interesting, b/c extending java.lang.Object
gives a default. From http://www.braveclojure.com/multimethods-records-protocols/:
(extend-protocol Psychodynamics
java.lang.String
(thoughts [x] "Truly, the character defines the data type")
(feelings-about
([x] "longing for a simpler way of life")
([x y] (str "envious of " y "'s simpler way of life")))
java.lang.Object
(thoughts [x] "Maybe the Internet is just a vector for toxoplasmosis")
(feelings-about
([x] "meh")
([x y] (str "meh about " y))))
Ah, yes, it does walk up the tree, where you would need prefer-method is things like interfaces
https://github.com/clojure/clojure/blob/master/src/clj/clojure/core_deftype.clj#L535-L544
@hiredman, could you point to me the part of the code of clojurebot, that regulates the allowed fuctions for input?
please 🙂
https://github.com/hiredman/clojurebot/blob/master/clojurebot-eval/src/clojurebot/sandbox.clj it is an ancient part of clojurebot, lots of legacy bits, most of it doesn't apply anymore since forms are not evaluated in the same clojure runtime as clojurebot
Promesa is awesome! I have some shared node/jvm code, and had to wrap everything in promises to get the same interface. Promesa solved that, and it also allowed me to do synchronous unit-testing because I can deref the promises on the jvm. So cool!
what is the other runtime?
clojurebot creates an isolated(ish) classloader and loads another clojure runtime in it and runs the code there
ah this security-manager thing 🙂 i have to read some manpages to understand that code. but thanks! 🙂
classloader isolation allows clojurebot to load another version of clojure and evaluate code in it, and keeps the user code evaluation environment distinct from clojurebot's
the securitymanger is wrapped around that to limit what code evaluated in that isolated classloader can do
How do you deal with java.lang.NullPointerException
bugs? It says nothing.... no file, no line, no reason.
depend on the version of clojure you are on *e will give you a data representation of the stacktrace
exceptions (with the exception of when the jvm optimizes them away, and there is a flag to turn that off) all have stacktrace information on them
In code, I have spec called ::credit-account
defined as (set (keys (config/chart-of-accounts)))
. The integration test uses a different chart of accounts to test. What is the best way to redefine the spec so the test can pass?
people have complained a lot about clojure stacktraces in the past, and unfortunately this has caused a lot of tooling to decide to hide or not display them by default, which is terrible when you know what you are doing and can read stacktraces
Traditionally adding more information to error also has the nasty habit of making some code slower (due to inlining limits and the like).
Esp, with NPEs where they often crop up when you call a function and the local that function is in is nil. Stuff like that is really hard to provide more information about as it affects every function call site.
But in that case a line number is often fairly helpful.
Another fun thing to watch out for is that the JVM will optimize away the stacktrace from a commonly occurring exception — so if the same code throws NPE repeatedly, subequent throws will “mysteriously” have no stacktrace even with *e
!
-XX:-OmitStackTraceInFastThrow
will be your friend (as a JVM option)
:let / :when works inside for ; are they also suppsoed to work under do-seq ? (I exepct them to, but I can't find it in clojure docs)
for is a special case https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L4604
user=> (doc doseq)
-------------------------
clojure.core/doseq
([seq-exprs & body])
Macro
Repeatedly executes body (presumably for side-effects) with
bindings and filtering as provided by "for". Does not retain
the head of the sequence. Returns nil.
nil
user=>
Hi all quick question how I can create a spec that allow nil or string values and for both return true
Right now I have this but not work:
(def non-empty-string? (s/and string? (complement empty?)))
(s/def :name (or nil? non-empty-string?))
@zerocooljs (s/nilable string?)
(it mentions nilable
directly in https://clojure.org/guides/spec )
https://github.com/jonase/kibit <-- where in this code does it parse the clj fiels?
@tanzoniteblack that works thank you!
@tanzoniteblack : I see it, thanks!