This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
Hey team, I discovered https://github.com/mozilla/mentat/tree/clojure -- a datomic-like wrapper over sqlite, built ~8 years ago.
I wanted to play with it, and am trying to run it on my computer. Right now, when I run lein deps
I get:
#:clojure.error{:phase :compile-syntax-check, :line 282, :column 1, :source "clojure/core/rrb_vector/rrbt.clj", :symbol deftype*}
I am guessing this is because the version of clojure / lein they used is quite ancient, and I need to go back to it.
Is there some incantation I can run with lein, which "sets" me into the same world that this library was in?Update: I realize lein already installs the older version of clojure (it is specified in the project.clj). I think I may need to downgrade the JDK. Will look into jdk version managers
My guess is you have lein plugin or something that is failing, what is the rest of the stacktrace
That looks like something is trying to load rbb-vector and failing because the version of clojure being used pre-dates deftype
It is extremely unlikely that something would specify an ancient version of clojure, but also try and require the rrb vector library, since the library didn't exist then
Which is why my guess is some bit of build tooling or plugin you have in your user profile or something is injecting some dependencies and causing some code to load
https://github.com/mozilla/mentat/blob/clojure/project.clj ^ this is their project.clj Oo will check if I have any plugins. Thanks @U0NCTKEV8 !
Maybe it is trying to load clojure source as clojurescript? You really need to look at the whole stacktrace to see what was being done
@U0C5DE6RK I cloned the repo, checked out the clojure
branch (with the project.clj
file) and got it running with JDK8: lein deps
or lein test
both work. It doesn't work with JDK11 or later.
All the dependencies in that project are pretty ancient so that's why they're not compatible with more modern JDKs -- so it might be a combination of updating all the dependencies and making some code changes if you want to try it with a newer JDK.
@U0C5DE6RK you may also want to look at https://github.com/tonsky/datascript-storage-sql
JDK 8 did the trick -- thanks @U04V70XH6 and team!
As a side note, I’ve been able to get Datomic-Pro working using SQLite as its storage service. I can share details if anyone is interested.
Hi, I am following a particular example in web on reducers. The task is to find the total number of children in a Village:
(def village
[{:home :north :family "smith" :name "sue" :age 37 :sex :f :role :parent}
{:home :north :family "smith" :name "stan" :age 35 :sex :m :role :parent}
{:home :north :family "smith" :name "simon" :age 7 :sex :m :role :child}
{:home :north :family "smith" :name "sadie" :age 5 :sex :f :role :child}
{:home :south :family "jones" :name "jill" :age 45 :sex :f :role :parent}
{:home :south :family "jones" :name "jeff" :age 45 :sex :m :role :parent}
{:home :south :family "jones" :name "jackie" :age 19 :sex :f :role :child}
{:home :south :family "jones" :name "jason" :age 16 :sex :f :role :child}
{:home :south :family "jones" :name "june" :age 14 :sex :f :role :child}
{:home :west :family "brown" :name "billie" :age 55 :sex :f :role :parent}
{:home :west :family "brown" :name "brian" :age 23 :sex :m :role :child}
{:home :west :family "brown" :name "bettie" :age 29 :sex :f :role :child}
{:home :east :family "williams" :name "walter" :age 23 :sex :m :role :parent}
{:home :east :family "williams" :name "wanda" :age 3 :sex :f :role :child}])
I have tried the following solution which does not seem to work(throws exception):
(def map-children-to-value1 (map #(if (= :child (:role %)) 1 0)))
(reduce + 0 (map-children-to-value1 village))
But if change it slightly, it works
(def ar (map #(if (= :child (:role %)) 1 0) village))
(reduce + 0 ar)
Could someone please explain why the first solution does not work.
(map f) ==> returns a transducer It doesn't return a simple function. I'm new to Clojure but I don't think you can use a transducer as the function parameter in reduce You could try this - make map-childeren-to-valu1 a function (defn map-children-to-value1 [x] (map #(if (= :child (:role %)) 1 0) x)) => #'get-started.hello-repl/map-children-to-value1 (map-children-to-value1 village) => (0 0 1 1 0 0 1 1 1 0 1 1 0 1) and pass that to reduce (reduce + 0 (map-children-to-value1 village)) => 8
Just curious. Did you mean to create a transducer in the first solution? https://clojuredocs.org/clojure.core/map
yeah mostly, but I wanted to define a separate variable for the long map expression.
Sorry, I forgot to respond in a thread, :face_palm: "I wanted to define a separate variable for the long map expression." I would move just the
#(if (= :child (:role %)) 1 0)
...into a standalone fn using defn
, then use it inside the reduce
fn. Let reduce iterate over village
, and the reducer +
handle the summing.Wait, that's a mess ^^^. brb
the reason the first example throws an error is that map with one arg creates a transducer (as was eluded to earlier), and transducers aren't quite functions that can be called in function position... they require a transducing context, like sequence
for example. There's a deeper explanation of transducers at <https://clojure.org/reference/transducers>.
To tweak the first example:
(def map-children-to-value1 (map #(if (= :child (:role %)) 1 0)))
(reduce + 0 (sequence map-children-to-value1 village)) ; => 8
; or even just
(transduce map-children-to-value1 + 0 village) ; => 8
A slight tweak that might be a bit shorter is:
(count (filter #(= :child (:role %)) village)) ; => 8
haha, I do not use reduce much, either! Agreed with @U013JFLRFS8 on the simpler solution using sequence operators. If the exercise really wants reduce
to be used, and we do not want simply to say (reduce + <a sequence>)
, you can do (tested!):
(reduce add-child-ct 0 village)
...and in the add-child-ct
function apply your logic to reach resident, adding the result to the first (accumulator) param.
Now as punishment for my sloppy help I will try again using a transducer. 🙂Ah, you were close @U06GX80NS78 :
(transduce map-children-to-value1 + village)
Tested. 🙂or this kinda cursed solution:
(transduce
(comp (map :role)
(replace {:child 1
:parent 0})) + 0 village)
@U06GX80NS78 I feel you can build on this idea:
(reduce
(fn [counts x] (update counts (:home x) (fnil inc 0)))
{}
village)
;=> {:north 4, :south 5, :west 3, :east 2}
Thanks everyone. I read on Transducer after seeing @U013JFLRFS8 comment. I think it is making more sense now on how the first example is not working. Also got a lot of different ideas to implement the same.
(reduce (fn [acc {:keys [home role]}]
(merge-with + acc (when (= role :child) {home 1})))
{} village)
Using just merge-with
to replace update
and fnil
in @U051MHSEK's idea.If you were to remove the check for (:role :child)
and use merge-with
alone:
(reduce (fn [acc {:keys [home]}]
(merge-with + acc {home 1}))
{} village)
It would still work correctly because merge-with
does not rely on the absence of a key to determine the default value, it simply merges the values of matching keys according to the provided function (`+` in this case).Which you can then generalize to find count according to the predicate passed:
(defn count-matches [target-key predicate accum-key coll]
(reduce (fn [acc item]
(merge-with + acc (when (predicate (target-key item)) {(accum-key item) 1})))
{} coll))
(count-matches :role #(= % :child) :home village)
(count-matches :sex #(= % :m) :family village)
(count-matches :age #(< % 18) :home village)
Edit: Swapped predicate, target-key order in args to give better reading.
:)More or less that. If the solution needs to be that general, I think I would lift out a "counter" method.
(defmulti counter ...) ; return the appropriate counter function
(defn village-stats
[stat-type villages]
(reduce (counter stat-type) {} villages)
(edit: with a little rejigging, the counter could emit a reducing transducer per stat-type.)Re: the merge-with
solution, I was thinking of the more boring alternative...
(reduce
(fn [counts x]
(if (pred x) ; e.g. child?
(update counts (:home x) (fnil inc 0))
counts)
{}
village)
Also, I noticed that if I use clojure.core.reducers instead, the code seems to work fine as well. Not sure how reducers map
is different compared to core map
(def map-children-to-value1 (r/map #(if (= :child (:role %)) 1 0)))
(r/reduce + 0 (map-children-to-value1 village))
This explains why, way better than I would be able to: https://www.braveclojure.com/quests/reducers/know-your-reducers/
I'm working on a CLJS app. After connecting to the shadow build, I can print
stuff and it shows up in my browser console as well as in my editor's REPL window. I'm wondering why the values print as I expect in the browser console, but show up like this in the REPL window:
; eval (root-form): (go (-> (http/send! client {:method :get :url "<https://h>...
#object[cljs.core.async.impl.channels.ManyToManyChannel]
whereas in the browser it just shows me {:foo bar}
(The real question is about good methods for finding Clojure resources for _____ when Google is not helpful.) Are there free resources about Clojure for data sciences? I am looking for a function to fit a Gaussian to a vector of [x,y] values. https://github.com/phronmophobic/dewey was not helpful for me. Neither was Google (irrelevant URLs, books which cost money for unlimited access).
In general, it can be difficult for any language to sort of centralize diverse sub-communities. IMO, this slack is probably the best way to get clued in to "where to look for X". To the specific question about data science, I'm aware of the scicloj community that is quite active in the clojure data science space. There's a site at <https://scicloj.github.io/> that has learning resources and libraries and that type of content. There are also some channels on this slack like #data-science and #sciclojml where folks might be able to make even more specific recommendations.