This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-04-14
Channels
- # beginners (53)
- # boot (93)
- # cider (13)
- # cljs-dev (17)
- # cljsrn (20)
- # clojars (1)
- # clojure (349)
- # clojure-austin (1)
- # clojure-gamedev (5)
- # clojure-italy (1)
- # clojure-nl (16)
- # clojure-poland (1)
- # clojure-russia (26)
- # clojure-spec (57)
- # clojure-uk (6)
- # clojurebridge (5)
- # clojurescript (145)
- # code-reviews (2)
- # core-async (88)
- # cursive (1)
- # datomic (3)
- # defnpodcast (10)
- # events (7)
- # hoplon (20)
- # instaparse (1)
- # jobs-discuss (15)
- # keechma (26)
- # lein-figwheel (2)
- # leiningen (1)
- # liberator (11)
- # lumo (40)
- # off-topic (54)
- # om (32)
- # onyx (11)
- # pedestal (6)
- # perun (4)
- # planck (6)
- # re-frame (4)
- # reagent (12)
- # ring (3)
- # ring-swagger (10)
- # rum (1)
- # testing (4)
- # timbre (1)
- # unrepl (20)
- # untangled (111)
- # vim (1)
you need to name each alternative, for another I think it has better behavior when used as a generator
@josh.freckleton yeah, that sort of join is basically O(n * m) (I think?), if you index the collections once you can re-use the collections . But if you're handling 10M rows, you're gonna be optimizing this for awhile. It's not exactly something you can hack out quickly.
How does something like SQL do it?
I mean, i started with a sql script that was fast, but, specs dictate this has to take place not in db.
lots of computer science, indexing, and very efficient structures. You're storing your data in lists, DBs often store data in hash map like things
sure, I'm with you there...
@josh.freckleton I;m in the middle of something, I'll write more in about 30min
@tbaldridge thanks so much!
replying here so we don't clutter main chat so much
awesome
So what you have in this code is basically a full table scan in SQL. The join is slightly faster by the fact that you're doing on-demand indexing (the first call to reduce). The problem is, you're throwing away the index after the join is finished.
So in SQL this sort of join is slow (left join over two unindexed tables). But in SQL you can generate indexes, and that's where it gets faster.
gotcha, ya those tables are indexed in sql
In SQL you'd create a index on your second dataset that says "index :aid". In clojure this looks something like (group-by :aid second-dataset)
totally, or clojure.set/index
Now the idea is that whenever you add data to the second dataset you also add it to that index. This reduces the performance of inserts, but improves queries. And most of the time since you read way more often than you write, that's just fine.
I'm with ya, that indexing cost is paid long before the query happens
right. That's the biggest computational difference. The other things have to do with hashmaps and how you access them. Now I'm not saying hashmaps are slow, but the rule is: when you do anything 10M times...it's all slow.
So SQL servers will also store data in very efficient data structures. In Clojure that would be something like using defrecord
instead of hashmaps, and perhaps even using (.-aid row) instead of (get row :aid).
ok, i wasn't familiar with that trade off.
i'd guess that defrecord
and hashmap
, while performance may be different, lookups still probably cost around O(log n), no?
Doing all that in Clojure ^^ isn't easy, but I have a query engine in production that can find 1.8mil results (involving about 5 joins per result) in about 27sec.
Right, and defrecord is basically the cost of looking up a pointer in a location of memory.
Also, if you know aid will always be a integer/long you can type-hint it, and that saves even more memory and a few pointer lookups.
ok, ya, it's always ints, that's a good point
You might even look into (deftype)
which is even more bare-bones, but also saves more space.
ok, i'll need to look into all of these, but I'm still not clear on my O(?) performance, that's probably my lowest hanging fruit
so do I sort all rows, and then do like @qqq is saying in the main thread?
that seems to make sense, but I haven't thought it through all the way yet
Yeah, I think he's right, at first I though you were doing: (for [a as b bs] join a with b)
, and that's O(m, n), but he's right, you're pre-indexing the collection, so it should be faster.
Do you have access to a profiler? If so those are a big help here as well.
I haven't had something this perf sensitive, so I'm not familiar, but I think I've read up on some good ones for CLJ
you mean one of those right?
Top of the line, IMO, is YourKit, so start there (I think there's a free trial).
It isn't cheap, but maybe you can convince your employer to buy a copy for the team
ok, great thanks!
And one last thing, if you get to the place where you need a ton of data in memory, and can sacrifice immutability, look into off-heap storage. Stuff like ChronicleMap are open source and don't store your data in JVM memory, so you can spend less time in GC collections, and still have access to GB of data.
but that may be way more than you need, lol
@souenzzo What are you using it for? Would this help? https://clojuredocs.org/clojure.core/some-fn
Question: Is there a map data structure, where each map entry can be safely updated. I could put a map in an atom, but that means if I'm updating two different keys at the same time, one will update will need to retry. So I want more fine grained control. Does that exist? Or even make sense?
@yonatanel My question is more for a function that test if x was something like a string
replying here so we don't clutter main chat so much
@tbaldridge : why is that join O(m * n) ? Can't you do better, like O(m log m + n log n + size of output) by (1) sorting both lists, and (2) marching down the two sorted lists in sequence (instead of having to look at all possible pairs)
@qqq yeah, I think you're right, I missed the on-the-fly indexing in the start of that function
@qqq that makes sense to me, so, my sort would be just the stock sort-by
on the keys that will be joined on,
and the march would be like 2 nested loop
s , right?
@qqq although I don't recommend sorting...sorting 10M rows is not a fun thing to optimize 🙂
Hm, I just set up a little test of sorting [{:a (rand-int 9999999)} ...]
100k -> 2 s
1M -> 23 s
10M -> still going after a couple minutes...
this might be crazy, but is there a way to get data from SQL already indexed?
like, some binary that jvm recognizes?
that would require some impossible voodoo on the gc I think
getting the data pre-sorted might help though
yes, most indexes store data pre-sorted, so getting an entire table sorted by the index should be fast
@yonatanel For now I avoided map literals, I didn’t get to the cause yet
anyone has an example for honeysql inserts to point at? I got a little lost on hooking it up through clojure.java.jdbc
I've built a statement with honeysql, but cannot find the clojure.java.jdbc
function that will simply execute it. It looks like insert!
expects a table name and row contents, not a sql statement (which I prepare with honeysql). Am I missing much, or is honeysql just practically superfluous when using clojure.java.jdbc
other than for sql queries?
I am also not sure from the http://clojure.github.io/java.jdbc/ whether statements are automatically "prepared" on their first use, or should be explicitly prepared, if one wishes to use prepared statements, I find the doc a bit ambiguous there. Your advice would be appreciated.
@matan you want execute!
query
is for selects, execute!
is for everything else. insert!
etc are just shorthand for SQL generation and then calling execute!
@seancorfield many thanks!
Also, read the expanded community-maintained docs at http://clojure-doc.org/articles/ecosystem/java_jdbc/home.html (linked from the readme).
And, yes, all statements are automatically "prepared" for you.
You can provide a parameterized PreparedStatement
if you want (instead of the ["sql statement" param1 param2]
construct if you want).
See prepare-statement
for more details.
Feel free to submit PRs against the community docs site if you have suggestions for how to improve the docs.
(Although no one does - they just complain 😸 )
query
also calls it, as do other parts of the library.
Thanks, I should look at the community docs indeed! I'll PR clojure.java.jdbc itself, to link there.
The repo DOES link to that!!
(And you can't submit PRs against control projects -- you have to submit patches on JIRA)
@josh.freckleton , @tbaldridge : I have never implemented this algorithm myself, but I think the details goes something like this suppose we have A :: list of objects of type a B :: list of objects of type b f :: a -> c // index function on a g :: b -> c // index function on b then, let X = intersection (f (A), g(B)) // takes O(m log m + n log n ) time then, for every x in X: run your op on f^{-1)(x), g^{-1}(x) f^{-1} and g^{-1} should be relatively cheap as you've indexed your data
this is inherently a little different from your "walk both at the same time", right? But the implementation is very straightforward, and I'm curious to understand:
so, for my understanding of big O,
- indexing presorted list costs O(m) + O(n)
- intersection costs O(m log m + n log n)
- lookup * 2 + merge costs O(log m + log n + merge)
where merge is.... m + n?
so in total, this specific algo would be O(m log m + n log n + m + n)?
and then if I walked both at the same time, like two nested loop
s, I could probably eliminate the lookup * 2 + merge portion, so my cost would probably be just:
- index both, presorted - O(m+n)
- walk them simultaneously - O(m+n)
so perhaps this one is better?
@josh.freckleton : you're right, if they're both pre-sorted, than you can "walk both at the same time" in O(m + n + size-of-output) time
@josh.freckleton : I'm currently hacking on something similar, but my rows are hashed, not sorted -- so I thought there had to be a cost for sorting -- but if they're already sorted, yeah, what you're suggesting is even better
also, I don't think it's two nested loops, I think it's just one loop; assume the keys for A are 2, 4, 6, 8, 10, 12, 14, 16 ; and the keys for B are 3, 6, 9, 12, 15
it'd be something like:
`
(let [as [2 4 6 8 10 12 15 16]
bs [3 6 9 12 15 18]]
(loop [as (rest as)
bs (rest bs),
fa (first as)
fb (first bs)]
(cond (= fa fb) (do processing; (recur (rest as) (rest bs) (first as) (first bs))
(< fa fb) (recur (rest as) bs (first as) fb))
:else (recur as (rest bs) fa (first bs))))
-- or something like that
where if cur-a = cur-b, we process
otherwise, we increment the smaller one by taking the next value from the corresponding list
thus "walking both lists at the same time"
oh nice, i'd thought of doing the same in two loops, but this is clearly better 🙂
I think we have to do it in one loop -- because if we have two loops, the and the outer loops M times and the inner loops N times then we get M * N, instead of M + N right?
the reason this one is only M+N is that each element of As is only consumed once, and each element of Bs is only consumed once
Ok. 1pm here. Bedtime.
Any built-in shorthand for defining a function that returns nil?
I have lots of functions that have no return value semantics, finishing up with nil
feels repetitive. Or should I change the way I think?
clojure functions always return something, there isn't an equivalent to void, except for interop
I have a (probably idiotic) question about the ..
member access macro. I'm working with mapdb and the following works:
(.keySerializer (.treeMap db "some-map-name") Serializer/STRING)
whereas the following doesn't:
(.. (.treeMap db "some-map-name")
(.keySerializer Serializer/STRING))
IllegalArgumentException No matching method found: .keySerializer for class org.mapdb.DB$TreeMapMaker
could somebody put me out of my misery and explain which part of my coffee cup i missed this morning...trying to tie together the nippy clojure serialization framework with the apache mapdb embedded database engine to get a "there is no database and we get to stay in our data oriented clojure world" scenario
these days ..
is not used that much as using ->
is more generic and as just as readable
ok duly noted, these are the kinds of things that you don't get from reading the doc strings
the advantage of using ->
instead of ..
is that if you want to thread a function call after a method you can
fun constellation, I'm implementing interfaces and overriding classes from mapdb, written in kotlin, in clojure...a blessedly java free experience
got another question, guess it was inevitable given my problem above : ). So I was implementing an interface in my first attempt, now I would like to override the following class from java (kotlin):
public class SerializerClass extends GroupSerializerObjectArray<Class<?>> {
ignoring the class hierarchy for a while, what is the correct way to subclass the above and override some methods from clojure?@mbjarland why not any of these? https://clojure.org/reference/datatypes
@bronsa yeah, kind of where I ended up, and I have no interest in exposing this internal implementation detail which I assume is what gen-class is for...which leaves us with proxy
is proxy dynamic as in every method call is somehow intercepted etc? guess what I'm asking is if there is a call overhead to proxy, I could potentially be calling this a very large number of times
@mbjarland would a few extra instructions on the CPU make a difference?
@matan normally no, but the reason we are using mapdb here is for performance and millions of reads, so in this scenario, maybe
@mbjarland good to know about mapdb I guess 🙂
A question about argument passing. I have this protocol method implementation in my code:
(log [this {:keys [text is-user time session-id]}] ; function body omitted
now if the wrong kind of map were to be passed here, all keys would just be nil
, whereas I'd appreciate some more safety. Of course I can :pre
my way though this, but how would you idiomatically go about it?
you can add some schema for validation https://github.com/plumatic/schema
or using clojure.spec https://clojure.org/about/spec
@U050PGQ9J thanks, I was hoping for some macro from clojure.core
or something. Assuming users of my library won't make mistakes shouldn't be part of clojure philosophy I think 😉
Maybe I'll just use java-like types! but I'm gonna take a longggg look at those two libraries you suggested
@U050PGQ9J wow great stuff to read through, guess it's not only my problem. eagerly reading those two resources...
there are some guides here fyr https://clojure.org/guides/spec
what’s the fastest serialization/deserialization format for clojure, i assume transit ?
i might actually benchmark the speed difference between cheshire and transit, cannot find anything on the internet about it..
Depends what on the other end
You haven't mentioned any binary formats like fressian, nippy, etc
i’m trying to balance between readability and performance — the latter one needs benchmarks, though
and cheshire is nice enough to include a bunch of benchmarks https://github.com/dakrone/cheshire/blob/master/benchmarks/cheshire/test/benchmark.clj
I was probably doing something wrong, as it was early on in my use of clojure, but if you're going to use cheshire, test it on large sets of data if that's something you'll need to do. I had to stop using it as it was truncating somewhere around 440K. As I said, probably my fault, but run some tests on your own data.
@lmergen I'd also try formats that retain types (like transit) before trying to use JSON. Dealing with date/float/url conversions to and from strings is a big pain.
Agreed, I've since switched to EDN
And isn't a computer going to read the data most of the time? Might want to optimze for that.
yeah, EDN works, but it's really slow.
@tbaldridge that actually is a good point, and transit is readable (enough)
I actually like being able to read the data, and it's helped with my debugging. And with EDN, it's the actual data, not something the other end has to transform, which is nice.
(oh and the * form does compile in CLJS and gives the correct (non-overflowed) sequence
Ah, standard *
is:
Returns the product of nums. (*) returns 1. Does not auto-promote
longs, will throw on overflow. See also: *'
Can someone give me a quick spiel about clojure.spec? I’ve been trying to grok the docs but i’m still not sure what it is
Have you seen the Rationale and Overview doc? https://clojure.org/about/spec
It’s basically a contract system. You specify what you data/parameters/return vals are supposed to look like, and clojure.spec
checks that for you at runtime
Check out the #beginners and #clojure-spec channels
anybody know of how you would go about performing polyglot compilation of clojure with other non-java languages (groovy, kotlin, scala) using leiningen?
So, in the CORS standard, browser's always do a pre-flight OPTIONS
call on any http route, right? so if there is a route (GET "/api/client/:client-id/record/:record-id"), a browser would actually make 2 calls to a backend service running on the same machine: curl OPTIONS
and curl GET
so the problem i'm running into is that we have to define a corresponding OPTIONS route for every other route I define
is there some way to mitigate that? I feel like this is a pretty common domain concern
in my experience that is not a true statement, that browsers always do an OPTIONS call…
@mbjarland compiling clojure and java on the same project with leiningen should give you some inspiration, there's an art for weaving the compilation stages
clojure and java I don’t have an issue with, I was looking for groovy-clojure, kotlin-clojure, scala-clojure
kinda gave up for now, seems to be few and far between hits on joint compiling anything but java
I think you might want to clump them together building each one with its own tool 🙂 sharing classes through directories
it does, not sure about cross language dependencies, I know it can do mutual between say groovy-java, but I’ll try not to ocd, I’ll just eat it and write some java
basically each language grown tool (sbt, lein, etc) is best at its own juice, but then things like getting a uniform java version, across-layers cleaning and artefact passing needs its own orchestration
frankly, even building scala with the scala tool itself (sbt) can make one pluck out their own hair in frustration on occasion.
I guess if I had to interleave different language-specific build tools by hand, using boot I would get all the flexibility I needed.
hopefully it is easy to weave external build tools with boot, and pass around artefacts between them through clojure code running under boot.
do take some time to grok filesets, tho. there is a bit of a learning curve. the folks on #boot are very helpful.
gradle does a beautiful job with groovy, scala, kotlin etc…and I just got it to work (unidirectional) between groovy and clojure (clojure calling groovy). But agreed, would not want to build a large clojure project with the somewhat thin clojure support in gradle
which speaks to the point that each language-specific tool is needed beyond the hello-world project complexity level per language
anyway, the guys at the sbt-dev gitter channel are somewhat cooperative, to help with any kind of integration
tried and failed to get bidirectional dependencies to work…does work between groovy and java, but not clojure groovy. Going to give up this particular experiment I think : )
anyway, in the far-out event that this would be useful for somebody: https://bitbucket.org/mbjarland/clojure-groovy-gradle
@mbjarland what do you mean by bidir deps? ( i did a fair amt of work with groovy once and it drove me to the brink of insanity).
bidirectional as in groovy can call java and java can call groovy…i.e. transparent source tree, you call what you want in any direction
not even sure if gradle does this for any other non-java hosted languages, I know it does do between non-java and java
with groovy-java there is no pain, it just works, but somebody sacrificed some lambs somewhere along the way
worked a lot with gradle for appengine. not bad (except for the groovy part), but really just more of the same build tool stuff. boot is in a different league alrogether.
: ) yes, I have even gone as far as to write a product which is partially based on gradle plugins
and I spent considerable time with groovy, but I am glad to hear that boot is that good…looking forward to grokking yet another awesome tool
boot has its pain points, but it's not really a build tool. it's more of a general job control language that happens to work beuatifully for sw building.
sovmuch of language preference is what you learn first and are most used to. i still like assembler, love C. ;)
oh and you can now write gradle scripts in kotlin if that makes you less sad : ) it does give you completion and type checking in IDEs which for build logic might not be a bad idea
so much stuff i want to check out, esp. when i already know a bit (groovy, gradle, kotlin, etc.) so little time.
true, and in the other direction for me, boot, a gazillion clojure frameworks, clojure script, reagent, etc
now I’m going to write some horrible java code and try to call clojure from it…think I need a drink first
yeah, i have to admit i spent a lot of time grokking boot. someday we'll get some decent docs.
Hey all, I've got some Java interop stuff that I'm not sure I'm doing the most effectively. I'm using Clojure to talk to Oracle Data Integrator's SDK. I'm having some success, but at the moment my code isn't the most intelligible!
A Groovy example can be found here: https://dylanwan.wordpress.com/data-integration-and-etl/odi-sdk-create-variable/
This specific line:
OdiProject proj = ((IOdiProjectFinder) mgr.getFinder(OdiProject.class)).findByCode("NEW_PROJECT");
I have the approx equivalent:
(.findByCode (cast IOdiProjectFinder (.getFinder (.getTransactionalEntityManager odi-instance) OdiProject)) "NEWPROJ")
I used cast, as my limited Java knowledge reminded me that's what was happening in the Groovy code, but is that the right way to translate to Clojure?
I've read that reify is for implementing Java interfaces, so would it be suitable for this, or am I misunderstanding?
cast guarantees that you throw an exception if the arg is not an instance of the requested type
reify, proxy, defrecord, and deftype are all viable ways to extend interfaces, they each have their use cases (more rarely, also gen-class) https://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/
Excellent, thanks @noisesmith will have a read now.
@matan built an executable jar with clojure calling a groovy class…I strongly suspect it is not bidirectional though
@danp also your code can look more like the original if you use ->
syntax to chain the method call forms
@noisesmith, so there's nothing particularly wrong with cast
? I'd not seen it anywhere, so was unsure whether it was particularly idiomatic. From the flowchart, it also looks like reify
is suitable the way I'm currently approaching it.
(-> odi-instance (.getTransactionalEntityManager) (.getFinder OdiProject) #_(cast IOdiProjectFinder) (.findByCode "NEWPROJ"))
; I commented cast as I don’t think its needed
Oh, thanks on the ->
... I'd experimented with doto
elsewhere in the code, but not thought of the ->
all cast literally does is throw an exception if the type isn’t an instance of the one asked for, but this can have a side effect that clojure knows which type you expect the compiled form to see at runtime which can be good
I am curious about future support for automagical generation of specs. I am not really focussed on the use case suggested by my example below, but more about the mechanics of using macros to generate specs:
(defmacro validity-wrapper [symbol spec]
`(do
(defn ~symbol [x#]
(s/valid? ~spec x#))
(s/fdef ~symbol
:args (s/cat (keyword (name 'x#)) ~spec)
:ret boolean?)))
In the above example, the presence of a list (keyword (name 'x#))
breaks validation of of s/cat
:
Assert failed: cat expects k1 p1 k2 p2..., where ks are keywords
(c/and (even? (count key-pred-forms)) (every? keyword? keys))
Would such nested evaluations be supported by clojure spec in the future?
@waffletower create the symbol outside of your syntax quoting, and you'll be fine
(let [x (gensym "x") x-kw (keyword (name x))] ... your code ...)
that’s fine by me, many thanks
@tbaldridge it would be fine to use (let [x (symbol "x")...
instead in such a context, right?
Changing my variable parameter to sym
first 🙂
cursive question: each time I restart the repl it ends up in what I assume is the user namespace, even if I load an entire clojure file in the repl (Shift-Apple-L in osx) the repl still stays in the user namespace. I have to do a (in-ns 'myns)
every time I restart the repl…which considering I’m tinkering with java is often. Expected behaviour or cursive issue?
I think that’s the expected behavior
but I think there is a different command to do the in-ns for you
^-Shift-N ?
@alexmiller well there is a “evaluate forms in REPL namespace” setting which is unticked
@alexmiller any idea what the command name is?
that’s for “Switch REPL NS to current file”
maybe I set that to match cider or something
I’ll send you my bill
now we’re talking - Laphroaig Quarter Cask? :)
Sounds right up my street tho’… For our first wedding anniversary my wife bought me a bottle of Ardbeg 25 yr old reserve. And I certainly do enjoy a Laphroaig 15 yr old (but not the 10).
you haven't lived until you've tried https://www.google.com/amp/s/www.thrillist.com/amphtml/drink/chicago/14-things-you-didn-t-know-about-malort-thrillist-chicago
Mal in swedish is moth and ört is herb, in olden days they believed the herb involved could repel moths…but yes, you can also die from it..wormwood I believe in English
look me up when you hit chicago (i don't think you can get it anywhere else). it really does taste like gasoline/kerosine - well, haven't tried either of those but they must taste like malort. but: it's a great medicinal the day after. ;)
Hey! @seancorfield I thought you were going to send it #off-topic . Oh no! My image of Clojurians is crumbling.
I figured it was “mostly harmless” in a thread… but, yeah, it went on a bit 🙂
I wish...
Just looked up the price for the Ardbeg and I finally find out what a marriage is good for 😄
Hey guys, i'm trying to use hiccup to generate a template, but it appears that element attributes need to remain static, or any symbols get picked up as 'strings' ie. `(let [class-local-var "class-foo class-bar"] (hiccup.page/html5 [:body {:class class-local-var}])` --> ...<body class="class-local-var">..... Any way to break out of this behaviour, and force it to evaluate the local var?
this seems to be the issue https://github.com/weavejester/hiccup/blob/master/src/hiccup/compiler.clj#L275
https://github.com/weavejester/hiccup/blob/master/src/hiccup/compiler.clj#L57 This is converting the symbols into strings
@benzap the macros in Hiccup are for pre-compilation. It should work with symbol bindings.
user=> (let [class-local-var "class-foo class-bar"]
#_=> (hiccup.page/html5 [:body {:class class-local-var}]))
"<!DOCTYPE html>\n<html><body class=\"class-foo class-bar\"></body></html>"
For Hiccup 1.0, presumably?
Yeah, looks like a bug. It’s partially fixed in Hiccup 2.0.0-alpha, but also blows up under some circumstances, so that needs to be fixed.
I’ll take a look at it, but it might be a week before I can fix it as I’m a little swamped right now.
Yes, please open an issue 🙂
is there a reason that I can get this to work:
(doseq [e '(r w)]
(println (swap-with-not-sublists li2 e)))
((w | s (not r)) (s | c) ((not r) | c) c)
(((not w) | s r) (s | c) (r | c) c)
=> nil
but when I try to adopt this to reduce it doesn’t:
(reduce swap-with-not-sublists li2 '(r w))
=> ((w | s (not r)) (s | c) ((not r) | c) c)
I'm trying to convert nested structures of vectors and hashmaps to nested structures of Java arrays and hashmaps, but I'm running into a mysterious array type mismatch error. Here's my code:
(defn- java-y [form]
(walk/postwalk #(cond (map? %) (java.util.HashMap. %)
(vector? %) (into-array java.util.HashMap %)
:else %)
(walk/stringify-keys form)))
(We were originally using clojure.java.data/to-java
, but couldn't figure out how it was supposed to work.)
if I recall, postwalk traverses through maps as a seq of map entries, and clojure map entries are likely also vectors
#error { :cause "array element type mismatch" :via [{:type java.lang.IllegalArgumentException :message "array element type mismatch" :at [java.lang.reflect.Array set "Array.java" -2]}] :trace [[java.lang.reflect.Array set "Array.java" -2] [clojure.lang.RT seqToTypedArray "RT.java" 1733] [clojure.core$into_array invokeStatic "core.clj" 3345] [clojure.core$into_array invoke "core.clj" 3334] [org.panlex.api$java_y$fn__1734 invoke "api.clj" 72] [clojure.walk$walk invokeStatic "walk.clj" 45] [clojure.walk$postwalk invokeStatic "walk.clj" 52] [clojure.walk$postwalk invoke "walk.clj" 52] [clojure.core$partial$fn__4759 invoke "core.clj" 2515] [clojure.core$map$fn__4785 invoke "core.clj" 2646] [clojure.lang.LazySeq sval "LazySeq.java" 40] [clojure.lang.LazySeq seq "LazySeq.java" 49] [clojure.lang.RT seq "RT.java" 521] [clojure.core$seq__4357 invokeStatic "core.clj" 137] [clojure.core.protocols$seq_reduce invokeStatic "protocols.clj" 24] [clojure.core.protocols$fn__6738 invokeStatic "protocols.clj" 75] [clojure.core.protocols$fn__6738 invoke "protocols.clj" 75] [clojure.core.protocols$fn__6684$G__6679__6697 invoke "protocols.clj" 13] [clojure.core$reduce invokeStatic "core.clj" 6545] [clojure.core$into invokeStatic "core.clj" 6610] [clojure.walk$walk invokeStatic "walk.clj" 49] [clojure.walk$postwalk invokeStatic "walk.clj" 52] [clojure.walk$postwalk invoke "walk.clj" 52] ...
far
=> ((w | s (not r)) (s | c) ((not r) | c) c)
(def bar '((w | s (not r)) (s | c) ((not r) | c) c))
=> #'math-stats.probability/bar
(= bar far)
=> true
(swap-with-not-sublists bar 'w)
=> (((not w) | s (not r)) (s | c) ((not r) | c) c)
(swap-with-not-sublists far 'w)
=> ((w | s (not r)) (s | c) ((not r) | c) c)
somehow bar and far are getting different results when passed into the same function, even though they are equal? anyone know how this could be ?@hiredman I also thought it might be that map entries are represented as vectors. Not sure how to get around that, though
I am sure @nathanmarz will tell you all about how to use specter to do it
@seancorfield , could clojure.java.data/to-java
be helpful for this?