This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-02-10
Channels
- # beginners (140)
- # boot (18)
- # cider (4)
- # cljs-dev (28)
- # clojure (191)
- # clojure-greece (51)
- # clojure-russia (1)
- # clojure-spec (13)
- # clojure-uk (2)
- # clojurescript (38)
- # community-development (26)
- # core-logic (16)
- # cursive (6)
- # datomic (3)
- # defnpodcast (9)
- # editors (1)
- # emacs (1)
- # fulcro (10)
- # immutant (3)
- # jobs-discuss (2)
- # leiningen (17)
- # lumo (24)
- # off-topic (30)
- # quil (12)
- # re-frame (11)
- # reagent (103)
- # remote-jobs (2)
- # shadow-cljs (157)
- # spacemacs (4)
- # unrepl (18)
- # yada (2)
if you want to use jdbc & postgresql in your app, how do you know which exact versions to use when you define the dependencies?
like this [org.clojure/java.jdbc "???"] [org.postgresql/postgresql "???"]
the version of postgres i have running locally is 9.6
@stevenpkent you can see the latest version of org.postgresql/postgresql on maven central, and the latest version of org.clojure/java.jdbc on http://clojars.org, also if you already have deps you can look for newer versions by using lein ancient
Contrib libraries are not on Clojars. They're on Maven.
@noisesmith thank you i will check it out
when people talk about “vars” in clojure/clojurescript, does that mean something more term-of-art than just a shortening of the word “variables”?
in clojure there’s a class clojure.lang.Var, each namespace owns a mapping from symbols to Var instances
a var is a mutable container holding a value
bindings created directly in let binding blocks are not Var instances though
#’foo returns the var holding the value you would get by using foo in the current scope (if it’s a var and not a local), and deref, @, or var-get will access the value it holds
that’s all in jvm clojure - last I checked clojurescript namespaces were not reified in that way, but I forget the specifics, perhaps someone else can fill in
interesting. i went down this rabbit hole precisely because of the #'foo
thing that I read about in a github issue on code reloading in clojurescript. for some reason remounting a component when you reference it as #'foo
works when just foo
does not. it doesn’t quite make sense to me why regular old foo
would ever refer to something different than #'foo
(assuming foo is not let bound anywhere)
consider what happens here:
(ins)user=> (def foo :a)
#'user/foo
(ins)user=> (def bar foo)
#'user/bar
(ins)user=> (def baz #'foo)
#'user/baz
(ins)user=> bar
:a
(ins)user=> @baz
:a
(ins)user=> (def foo :b)
#'user/foo
[A(ins)user=> bar
:a
(ins)user=> @baz
:b
when you capture the var, you see updates even when it was passed as an arg (rather than a compiled form, which automatically uses the var for you)
if you capture the value and not the var, you don’t see updates if you don’t compile a form using the name
@lee.justin.m so in cljs, consider what happens if you mount a component using something passed as an arg - if it’s just the value, you don’t see changes made by def unless you remount or otherwise recalculate, but if you used the var you would automatically use the new value without having to recreate anything
got it. yea that makes sense. that’s precisely the issue: namely that the top level component would not be re-rerendered though its children would be. thanks again!
also, you can call a var - it will automatically deref itself and attempt to call the value it currently holds
which is why you can eg. pass a var to a first class function
(ins)user=> (@#'+ 1 1)
2
(ins)user=> (#'+ 1 1)
2
equivalentfun fact, refs do this too (but atoms and agents do not)
(ins)user=> (def plus (ref +))
#'user/plus
(ins)user=> (plus 2 2)
4
Contrib libraries are not on Clojars. They're on Maven.
(ins)user=> (def add (atom +))
#'user/add
(ins)user=> (add 2 2)
ClassCastException clojure.lang.Atom cannot be cast to clojure.lang.IFn user/eval198 (NO_SOURCE_FILE:38)
i suppose that’s why you can just create [#'component]
instead of [component]
and it works, because somewhere the hiccup interpreter calls #'component
as a function
refs predate atoms and agents, but are much less popular now
editor question: parinfer infers parens based on indentation. does the reverse mode exist? i.e., infer indentation of the remainder of the current form based on parens? often i add some code in the middle of the function and it requires me to manually reindent the remainder of the function to keep the structure the same
I don’t know about a mode that does it automatically, but every editor should reindent current form with a simple keystroke
(in my experience both emacs and vim do this with the barebones clojure mode packages)
oh I misunderstood - you want this to happen while using parinfer… I’m surprised there isn’t some convenience to reindent children as you type
(similar to insert vs. replace mode)
I’ve been skeptical of parinfer since a repeated problem involving one co-worker who never indented correctly and another who let parinfer re-parenthesize code on every file they opened
of course there’s at least three problems here, even if parinfer is one of them 😄
well i am the master of my own domain. i also go really used to prettier in javascript and now i can’t stand to do anything myself 🙂
there’s cljfmt if you like auto-formatters, I swear by it
clojure puzzle website idea: it gives you the code but without the parens (or in advanced problems, the parens in the wrong places) and you fix the code by inserting the right delimiters
unlike 4clojure it could be beaten by a trivial ai using trial and error
i think i tried cljfmt and terrible things happened. but it might have been when i was using a library with big weird macros (rum) and it didn’t get them
that makes sense - you can tell it how to indent certain macros
i generated a new re-frame project using the command lein new luminus demo +re-frame
. it works fine when i run it as is, but when i ^:export
the main function and try to run it directly in my html file using demo.core.main
, it doesn’t work. the error i get is Error: _registerComponent(...): Target container is not a DOM element.
.
it’s confusing why this doesn’t work since the examples in the re-frame repo all do it this way, i.e. https://github.com/Day8/re-frame/blob/master/examples/todomvc/resources/public/index.html
Is there an issue with cljs.ajax/GET and the handler not working well with a re-natal (reagent/re-frame) project ? I can't seem to set up a handler callback that does anything other than error out after the XmlHttpRequest state changes
@feihong.hsu if you only want re-frame without a backend in your project, you need to use the re-frame template. Luminus always includes a clojure backend, which you don't seem to need.
Why this error message :
Exception in thread "main" java.io.FileNotFoundException: Could not locate guestbook/db/migrations__init.class or guestbook/db/migrations.clj on classpath., compiling:(guestbook/test/db/core.clj:1:1)
at clojure.lang.Compiler.load(Compiler.java:7526)
at clojure.lang.RT.loadResourceScript(RT.java:379)
at clojure.lang.RT.loadResourceScript(RT.java:370)
at clojure.lang.RT.load(RT.java:460)
at clojure.lang.RT.load(RT.java:426)
at clojure.core$load$fn__6548.invoke(core.clj:6046)
at clojure.core$load.invokeStatic(core.clj:6045)
at clojure.core$load.doInvoke(core.clj:6029)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5848)
at clojure.core$load_one.invoke(core.clj:5843)
at clojure.core$load_lib$fn__6493.invoke(core.clj:5888)
at clojure.core$load_lib.invokeStatic(core.clj:5887)
at clojure.core$load_lib.doInvoke(core.clj:5868)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$load_libs.invokeStatic(core.clj:5925)
at clojure.core$load_libs.doInvoke(core.clj:5909)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$require.invokeStatic(core.clj:5947)
at clojure.core$require.doInvoke(core.clj:5947)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$apply.invoke(core.clj:652)
on this code :
(ns guestbook.test.db.core
(:require [guestbook.db.core :as db]
[guestbook.db.migrations :as migrations]
[clojure.test :refer :all]
[clojure.java.jdbc :as jdbc]
[guestbook.config :refer [env]]
[mount.core :as mount]))
(use-fixtures
:once
(fn [f]
(migrations/migrate ["migrate"])
(f)))
(deftest test-messages
(jdbc/with-db-transaction [t-conn db/conn]
(jdbc/db-set-rollback-only! t-conn)
(let [timestamp (java.util.Date.)]
(is (= 1 (db/save-message!
{:name "Bob"
:message "Hello World"
:timestamp timestamp}
{:connection t-conn})))
(is (=
{:name "Bob"
:message "Hello World"
:timestamp timestamp}
(-> (db/get-messages {} {:connection t-conn})
first
(select-keys [:name :message :timestamp])))))))
`if there's a migrations.clj file, it isn't in the right place relative to your classpath
I don't think this has anything to do with windows - where's your migrations.clj file?
there is never a migrations.cli made when I search in my code : https://github.com/RoelofWobben/guestbook
well that would explain the error
you can't call code in a file that doesn't exist
I think I give up on clojure. First problems with the template that files are missing and still running into that
Hey, I’m just have started play around with Clojure and transducers.
I’ve implemented the “string compression” function, which is just a simple problem from hackerrank. I’ve decided to implement it with function chaining ->>
and transducers and measure the speed.
At the beginning I was thinking, that I should always favor transducers wherever possible, but now after watching Rich’s video on transducers I’m kinda confused.
Code
(defn string-compression-1
[s]
(->> s
(partition-by identity)
(mapcat #(if (> (count %) 1)
(list (first %) (count %))
(list (first %))))
(apply str)))
(def xform-str-compr
(comp (partition-by identity)
(mapcat #(if (> (count %) 1)
(list (first %) (count %))
(list (first %))))
))
(defn string-compression-2
[s]
(transduce xform-str-compr str s))
Question/Problem
My functions are not completely the same, right? I’ve been watching a transducer video by Rich and he showed the abstraction of the map
with the help of step
function. So in my case, the step function is str
, which means, that I will call str
function on all my intermediate results, right? Whereby the example with ->>
will call the function str only once which should be definitely faster, right? My point is, it wasn’t smart using str as a step function, right? What are your thoughts on this?you could try two things here: (fn ([] []) ([x y] (conj x y)) ([xs] (apply str xs)))
or (fn ([] (StringBuilder.)) ([x y] (.append x y)) ([sb] (str sb)))
(each of those could replace str, that is)
oh scrolling down I see these points have been made
Why do people use variables named post-id
instead of postId
in Clojure?
Where does this convention/habit come from?
Do I need to do the same?
@vincent.cantin when people learn new languages, they often like to carry over conventions -- i think its useful though to fully embrace existing conventions in the new language
i started with php, then python, then javascript -- all three with different naming conventions -- every time i tried to carry over the conventions from the former
1) you have to assume that other coders follow the languages mainstream conventions, so when you ask them to read your code, you make it harder for them 2) reading other peoples code makes it harder for you 3) you end up in these absolutely pointless debates about naming conventions
@denisgrebennicov Yes correct, your str
function will be called over and over and a new JVM string is constructed on every step of the transducer
Though, quote "should be def. faster" isn't true. Since your runtime isn't dominated by constructing the string
@vincent.cantin I think snakeCase sucks and in lisps I have the opportunity to use the much better kebab-case instead. You're free to disagree and write your code like that though!
It's most likely because you're constructing data structures and intermediate lists/seqs in those steps. The transducers avoid that, hence they're likely faster in your case
@rauh but of course, what is more important is the general understanding of what I am doing 😅 My assumption was that applying str on a collection is relatively fast, because of the String Builder appending it to a buffer and then returning a string (don’t know how it’s really done, but rather my intuition) Whereby creating a new String on my intermediate results just doesn’t sound right. Can I somehow make the code better, clearer?
@denisgrebennicov You're absolutely correct. But creating the final str isn't your 80% time of the algorithm. It's all the other stuff it's doing. Clearer? Unlikely, but certainly faster is possible. You can do use a StringBuilder
as reducing function and make it faster, but that's extra (coding) work
@denisgrebennicov It only matters ~25%:
(transduce xform-str-compr str-reducer (StringBuilder.) s)
(defn str-reducer
([] "")
([x] (str x))
([^StringBuilder sb x] (. sb (append (str x)))))
@denisgrebennicov Also you could avoid the mapcat:
(def xform-str-compr
(comp (partition-by identity)
(map #(if (> (count %) 1)
(str (first %) (count %))
(str (first %))))))
FYI @rauh @denisgrebennicov I just benchmarked the StringBuilder vs. the str versions, and the naiive version was 7.728926 µs, transducing with str was 3.031921 µs, and transducing with StringBuilder was the worst: 111.232498 µs
@noisesmith No way, type hinted?
oh, I left out a type hinting - trying that again
OK - type hinting brought the StringBuilder version down to 2.582512 µs
which is much closer to expected, but still a very small improvement
I benchmarked with a relatively short string though, you'd see bigger differences for longer strings I'd assume
oh, and the solution switching mapcat/list to map/str is negligibly faster - the difference is statistical noise
@here I’m looking for some advice on tooling setup for a Reagent/Reframe ClojureScript project I’m working on. I think it will be using boot, although that could change. I’d like to understand what this channel would recommend for basic front-end stuff like Sass/CSS Modules compilation, Sass/CSS linting, hot reloading and a component library?
@noisesmith @rauh thank you for your help! Learning something new everyday. PS. what have you been using for benchmarking? [Criterium?](https://github.com/hugoduncan/criterium)
yes, that was all using criterium
also, in real code, before even using criterium or speculating about speedups, you should usually 1) wait until you discover that things are not fast enough and 2) profile (eg. with yourkit or visualvm) to see what the actual speed bottlenecks are
yes, I assumed that
I just see a lot of time wasted on speculative optimizations in a program that doesn't even run yet, or in a part of the program that isn't slow
(in my professional experience that is)
like the time I wasted weeks on streaming html parsing to replace an eager scraper, when the actual problem was (doseq [x input] (future (scrape-html x)))
which is just about guaranteed to be pathological and quite easy to fix
@noisesmith so if you were in my shoes, you wouldn’t be using transducers in this case? (I’m not talking about optimizing the code). Assuming that you were able to pick which implementation to choose, which would it be?
often a transducer is a drop in 1 for 1 replacement for ->>
surrounding collection operations
in that case, it's a trivial choice - the arrow macros are severely overrated, the transducing is as easy to read and think about, and easier to decompose and abstract, so always do it
even if performance were not an issue, (comp (map f) (filter g))
is empirically better than #(->> % (map f) (filter g))
and it turns out, as a bonus, that also performs better
and you can still use transducers inside a lazy process, via eg. sequence or eduction, though the translation isn't always worth it
@rauh but you can use transducers
with sequences
right? making it lazy. Or am I wrong?
sequence has some drawbacks depending on what you are trying to do - eg. it chunks which isn't always what you want (though arguably if chunking is a problem you might not want laziness anyway)
so yeah, I should correct what I said above, using transducers is a no-brainer if eagerness suffices, for laziness some other questions come into play
this might help illustrate it
+user=> (let [s (sequence (comp (take 3) (map #(doto % print))) (range))] (doall s) (println) s)
012
(0 1 2)
+user=> (let [s (take 3 (sequence (comp (map #(doto % print))) (range)))] (doall s) (println) s)
01234567891011121314151617181920212223242526272829303132
(0 1 2)
fixed the paste, it was very ugly before -- in the first case, the take transducer controls consumption so we don't process more than 3 items, in the second case the take is outside, so sequence chunks the processing into blocks - the minimum number of items processed is 32
and if you asked for 34 items, it would process a total of ~64, etc.
this is done because for most cases, processing 32 items at a time performs better than 1 at a time
Hey all! I came across '(dracula dooku chocula)
in https://github.com/functional-koans/clojure-koans, what exactly is it that's created there?
a list of symbols
a nice thing with clojure is that with a repl, it makes it easy to investigate this thing interactively
user=> (map type '(dracula dooku chocula))
(clojure.lang.Symbol clojure.lang.Symbol clojure.lang.Symbol)
@andy.fingerhut of course! (list 'one 'two 'three) == '(one two three)
you got it
turn that facepalm into a bright lightbulb shining over your head! 🙂
this behaviour seems surprising to me
user=> (subvec [:peanut :butter :and :jelly] 1 3)
[:butter :and]
user=> (nth [:peanut :butter :and :jelly] 3)
:jelly
the end index is exclusive, not inclusive
so a range from 1 to 3 will include indexes 1 and 2
user=> (doc subvec)
-------------------------
clojure.core/subvec
([v start] [v start end])
Returns a persistent vector of the items in vector from
start (inclusive) to end (exclusive). If end is not supplied,
defaults to (count vector). This operation is O(1) and very fast, as
the resulting vector shares structure with the original and no
trimming is done.
nil
fair enough, it does seem odd to be provding an index that's outside of the vector to retrieve it's contents but ¯\(ツ)/¯
this is really common across a lot of languages for getting array slices. one benefit is that the exclusive “end” == count. another is that you can take subsequent slices and use the exclusive end value as the next inclusive begin value, so turns out to be good for walking through a structure and taking slices.
you don't need to provide an end index for that
user=> (subvec [:peanut :butter :and :jelly] 1)
[:butter :and :jelly]
"Maps can be used as functions to do lookups"
(= 1 ({:a 1 :b 2} :a))
this is interesting, does this idea of using a data structure as a function (or other non functions) pop up in other places?hash-maps, keywords, vectors, symbols and sets all act as functions doing lookup as if you called get
it's also easy to create a custom data object using defrecord or deftype that acts like a function in any way you prefer
user=> [(:a {:a :keyword})
(:a {:b 1} :not-found)
('a {'a :symbol})
({"a" :hash-map} "a")
([:x :vector] 1)
(#{:set :y} :set)]
[:keyword :not-found :symbol :hash-map :vector :set]
thanks @noisesmith that's very helpful
Is this koan written wrong or am I missing something? Given
"Higher-order functions take function arguments"
(= 25 (___
(fn [n] (* n n))))
then shouldn't the solution be
"Higher-order functions take function arguments"
(= 25 (
(fn [n] (* n n)) 5))
?