This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-07-07
Channels
- # babashka (7)
- # beginners (218)
- # boot (1)
- # chlorine-clover (2)
- # cider (36)
- # cljsrn (8)
- # clojure (71)
- # clojure-dev (9)
- # clojure-europe (11)
- # clojure-france (1)
- # clojure-italy (5)
- # clojure-nl (5)
- # clojure-uk (24)
- # clojurescript (9)
- # conjure (16)
- # cursive (65)
- # datomic (76)
- # devcards (21)
- # emacs (1)
- # etaoin (1)
- # figwheel-main (47)
- # fulcro (37)
- # hyperfiddle (9)
- # java (2)
- # kaocha (1)
- # malli (11)
- # music (14)
- # observability (8)
- # off-topic (32)
- # re-frame (13)
- # reagent (2)
- # reitit (5)
- # ring (3)
- # shadow-cljs (40)
- # slack-help (17)
- # spacemacs (15)
- # tools-deps (5)
- # xtdb (16)
Hi everyone! I am using emacs cider for Clojurescript. After cider-jack-in-clojurescript
, I cannot get any autocompletion for js/
(I would expect some candidates like js/Document
). It could be due to this issue (https://github.com/rksm/clj-suitable/issues/15). Does anyone know how to get around this problem?
@haoyuan80s Since that's a pretty specific question, you might get a more useful answer in the #cider and/or #shadow-cljs channels.
(although, reading that issue, I suspect that rolling back to shadow-cljs 2.9.x would solve the problem @haoyuan80s?)
is there a way to get clojure.data.xml/parse
to ignore leading indentation/whitespace when the input is pretty-printed? I don't have control over the input, not all input is indented, and I get it as a byte[]
from a queue initially so I was trying to avoid processing as text to trim prior to parsing if there's some way to get it done by the parser.
Alternatively, I guess I'd like to filter all elements of the form "\n "
in the :content
of all tags in the parsed map. (various numbers of spaces and arbitrary levels of tag nesting)
There are some parser options you can set on parse - I think of you set :coalescing to true maybe that does what you want?
thanks, I tried :coalescing true
but didn't seem to make a difference. currently using clojure.walk/postwalk
to remove indentation strings from the parsed content, but not sure if there's a more idiomatic/performant way to go about it.
current approach looks roughly like
(comment (->> (io/input-stream (rand-from-corpus))
(xml/parse)
(clojure.walk/postwalk #(cond (and (string? %) (re-matches #"^\n\s*$" %)) nil ; remove indentation
(seq? %) (keep identity %) ; remove the nils created by removing indentation
:else %))
(xml/emit-str)))
If I have 3 vecs -- x, y, z, what's the idiomatic way to create this new vec? [x1 y1 z1 x2 y2 z2 x3 y3 z3]
@dpsutton Little typo here, the missing quote I think (interleave [:a :b] '(1 2 3))
Why does this output nil?
(= nil (if (nil? 0)
[:a :b :c]))
;; nil
it doesn't it returns true
and nil isn't equal to 0
hmm. my REPL outputs nil, which is why I'm confused
I was working on this problem set https://github.com/mkaschenko/clojure-koans/blob/master/07_conditionals.clj
lines 20-22
I think it's trying to teach you that 0 isn't nil, but doing it in a very weird way
that was a typo, my REPL outputted nil
it's odd to have = nil
and nil?
in the same code
that link is the solution branch. I'm working on the fill-in-the-blank branch
I've seen it in a lot of tutorials as just a way to show you what the concept they are teaching will result in.
I played around and it wasn't clear to me until now that nil
is the default output if the output for a false condition isn't explicitly stated.
(if (boolean? "not a boolean") true)
;; nil
(if (boolean? "not a boolean") true false)
;; false
FWIW if
treats nil the same as false, and that's what matters most of the time in application logic (very rarely does one explicitly need false)
Thanks for the help and clarification everyone.
in many languages 0/nil/false are all the same value, in clojure they are three different values
the boolean of all values that are not nil or false is true
this isn't machine language
yeah @noisesmith understand. i was expecting some logical response by casting to boolean 0
or ""
But its right.
For Leiningen there's lein-ancient
and for deps.edn
there's Depot so you can look at the code for those.
I think you could also just use tools.deps.alpha
directly and use "RELEASE"
as the version in the coordinate... I'm not sure what in that library exposes the actual version resolved tho'
hah, but it's untrue, Depot is unmaintained but it links https://github.com/liquidz/antq
I'd hardly say Depot is unmaintained https://github.com/Olical/depot/commits/master
(I know he says that in the README but he's been updating the code quite a bit lately -- so that's a bit of a contradiction 🙂 )
My problem with Depot (since 1.8.4) and with projects like antq is that they assume they can just read your project file and figure out everything from that alone -- which just isn't true.
What do you mean? I just want to know if someone published a newer version of a dependency
We had to stop using Depot because of that (and we wouldn't be able to use antq either) -- which is why I suggested using t.d.a. directly.
Because deps.edn
alone doesn't provide the full story, e.g., if you're using aliases to :override-deps
from a user-level file (as most folks with monorepos do -- using CLJ_CONFIG
to treat a master deps file in the repo as the "user-level" file to combine with the project deps file).
I am coming from javascript. We had a package.json. If it wasn't in a package.json, it wasn't part of the project. I do not intend to change this practice transitioning to clojure
You can ignore the user-level deps.edn file by specifying -Srepro
-- and then your project-level file is the whole world.
btw and fyi 🙂 I am using your dot-clojure with tiny modifications as my $HOME/.clojure/deps.edn I think you had some tutorial with it on youtube, good stuff
so it had the outdated alias for depot all this time, and I was wondering why my copy paste shows a linting error :D
Ah, yeah. It uses 1.8.4 because that version actually relied on t.d.a. to process dependencies, just like clojure
/`clj` would. In the 2.x version, it tries to just read the file (which doesn't work for us).
the castings polymorphisms for nil are a bit wierd and seem arbitrary at first
• nil is cast to empty list by cons
and conj
• nil is treated as a false value by if
and all the macros built on it
I think the nil/false/0 vs. nil/falsey/() split is about Algol vs. LISP heritage, and most languages used today are descended from Algol
and java shares bits of each side
and clojure takes that and tweaks it some more to be lispier
"cast" is the wrong word here. it is better to think about it as "how does operation X work polymorphically on nil"
thanks, that's a good point
and "nil is treated as a false value by `if` and all the macros built on it" is really about the definition of logical truth in Clojure, not "treated as false"
logical truth of an expression = false if value is nil
or false
, true in all other cases
but even here you use "false" twice
(with two senses, which I wasn't clear enough about distinguishing myself)
boolean
is the function that represents logical truth
that is a coercion from <any> to true/false
but even that doesn't reflect the behavior of if - they two diverge for instances of "false" that are not the static Boolean/FALSE (which of course doesn't matter as long as you never use the constructor for Boolean)
well, I'm happy to ignore the case you should never use
hi, is there a way to get the index of an element when using reduce
?
I have a vector [[:a 5][:b 6][:x 0][:label "foo"][:y :g][:label "bar"]]
And I'm trying to get a map out of labels and locations that would have {"foo" 3 "bar" 5}
that I can use as a lookup later.
I have
(reduce (fn [a i] (if (= :label (first i))
(assoc a :i)
a)) foo)
I was hoping i could put something like (reduce (fn [a i ix] ... ) foo (range)))
but no 😞i do the map vector because i always forget which order the index and the item are in for map-indexed
also, often the real solution is to rearrange your data or your algorithm so you don't have to switch between indexed and sequential representations/access
another nice trick is to create a map from position of element to element: (zipmap (range) coll)
user=> (pprint (zipmap (range) [:a :b :c :d :e :f :g :h :i :j :k :l]))
{0 :a,
7 :h,
1 :b,
4 :e,
6 :g,
3 :d,
2 :c,
11 :l,
9 :j,
5 :f,
10 :k,
8 :i}
nil
I presume you guys use the repl a lot. Do you run into issues where you end up losing code, or having to scroll way back up a lot, or are you continunally copying and pasting from the repl into your soure file as soon as its right? Or is their a workflow I'm missing here?
As has been mentioned already, using the editor is typically more productive. The most common editors seem to be http://practicalli.github.io/clojure/clojure-editors/
I do most work in my editor, only working directly in the repl for raw experimentation (seeing how some API works etc.)
some people swear by never typing directly into the repl
you can copy into the repl from editor, and most editors have shortcuts for sending to a repl
though I prefer integrations that have a true repl session showing all inputs and results
that's a personal choice, but I use neovim with the neoterm plugin for sending code to an embedded terminal
any decent code editor should have some feature
emacs (CIDER) and Intellij (Cursive) are quite popular
@qmstuart Try to develop a workflow where you never type into the REPL: use your editor, eval code into the REPL from there. That way you always have all your code saved for future use.
Watch Stu Halloway's presentations "Running With Scissors" and "REPL-Driven Development".
If you don't mind paying for an online course, look at Eric Normand's "REPL-Driven Development" on http://PurelyFunctional.tv
oooh, i've bought a couple of videos of http://purelyfunctional.tv, bought his DSLs one and one on re-frame. THey were both really good.
The REPL one is excellent! I loved it!
Im finding intellij mouse hover over a command and I get a pop up with the clojure docs to be EXTREMELY useful
What he teaches is applicable to all editors. I don't remember whether/how much he covers IntelliJ.
the documentation story in cursive is extremely nice. control-j and alt-space are just fantastic
I use Atom with Chlorine and I get popups as I type that show vars and functions, with their arglists inline and their docs below the suggestions.
I can also see docs inline in the code with a hot key if I want them onscreen to read while coding.
Example: as I typed (ass
I get possible completions and can move the cursor up/down to see arglists and docstrings inline.
Arglists and docstrings show up as I move the cursor down the list:
I get similar, but also get what seems a lot of information that isnt' all that helpful :S
I'm surprised it shows private functions. I shouldn't be surprised it shows all the Java stuff, being IntelliJ. You can call private functions, with #'
in front of them, BTW.
Hi, I am learning clojure, coming from nodejs/typescript. And I have a question, what is the idiomatic way to implement code below in clojure?
type Balance = {
amount: number;
};
interface IPayment {
sendMoney(balance: Balance): Promise<Balance>;
}
class PaymentServiceA implements IPayment {
async sendMoney(balance: Balance) {
// do something
return balance;
}
}
class PaymentServiceB implements IPayment {
async sendMoney(balance: Balance) {
// do something
return balance;
}
}
It kind of depends, there isn't really a single thing promises map to, if you are using clojure and not clojurescript, you might even not do anything at all and just block a thread (you can have many threads for cheap)
As far as polymorphic dispatch, there many choices there as well, multimethods are a decent starting point
yes, I think my question was more into protocols, how to implement it properly, and make sure the correct data returned by functions sendMoney
in my example above
as beginner, coming from a language like typescript you are likely to reach for defining new types too often, and protocols just sort of make that worse
you can use protocols without defining new types now, but for a long time that has not been the case, so most of the documentation etc. you see for protocols will show it used with defining types
so for example, if sendMoney is actually the same for all payment services, and all paymentservices are just a map with a balance key
then the polymorphism disapears and you just have a single function that takes any map with the right key
that's true. How you would design this heavily depends on what it's actually supposed to be
And the function results in some request over the network with authorisation and everything?
In that case I'd also recommend looking at multimethods first. Chances are this can be done nicely with a multimethod that takes a map representing the service and the money. Something like this:
(defmulti send-money (fn [service amount] (:type service))
(defmethod send-money :paypal ...)
(defmethod send-money :btc ...)
And then you would pass a map like this as the first arg:
{:type :paypal
:auth {...}
:whatever-else "is needed"}
Sure, you could make specs for the service map. I've personally never used spec but depending on the properties all services share and so on it may surely make sense.
I'd be similarly cautious with spec as you would be with protocols and records - they aren't a type system and aren't really something to declare for every function like you would types, they work best as something to validate things that cross system boundaries
> @hiredman: I’d suggest not using protocols I’m curious, what is the motivation behind this recommendation?
because this is #beginners and the original asker mentioned coming from typescript, and refuges from typed langues tend to reach for types and type based polymorphism over using simple datastructures like maps, sets, and vectors
@vasergen then your code isn't polymorphic
not sure what does it means. I just want to implement a special usecase and make sure that schema of input/output between different services the same
so you want polymorphism between services
and want a single spec across the implementations
I guess I find this strange because one of my first design rules for crossing system boundaries is that I keep the crossing points as simple and narrow as possible. If I'm not crossing a boundary I usually don't need a spec. If I am crossing one I know the precise data that is needed / accepted and do conversions to match on each side.
one thing that might be missing / implicit here is that there's a strong preference in clojure to use a small set of data types (mainly the ones that are built in) with a large number of functions on them
it's alien when coming from a lang like ML or typescript or whatever, but there is a logic to it
I think the best clojure book for this is Zach Tellman's Elements of Clojure https://leanpub.com/elementsofclojure
but I think there are other resources from common lisp / scheme that others could recommend
eg. I think I picked up the "small number of data types with a large number of functions" idea from SICP, but it's been long enough that I'm not sure
Is this a known ClojureScript limitation? Functions don't get spec validation when they are references at the same scope level of the namespace, or am I doing something wrong?
(defn f [x] (+ 1 x))
(spec/fdef f :args (spec/cat :x int?))
(def m {"foo" f})
;; properly fails spec validation
(f "bar")
;; does not fail spec validation
((get m "foo") "bar")
I would have been surprised if that worked - spec attaches to the metadata, the function itself isn't used to store the metadata (at least on jvm clojure)
Hello. I am trying to do something with spec but I am having toruble when it comes to generators. I have the function and spec
(defn lowest-val
"Given two keys x and y, returns the key with the lowest associated value in
m. Returns nil if the values are =."
[m x y]
(let [m (select-keys m [x y])]
(case (compare (-> m first val) (-> m second val))
-1 (-> m first key)
0 nil
1 (-> m second key))))
(s/fdef lowest-val
:args (s/and (s/cat :m (s/map-of keyword? integer?) :x keyword? :y keyword?)
#(contains? (:m %) (:x %))
#(contains? (:m %) (:y %)))
:ret any?)
(s/exercise-fn `lowest-val)
but when I call exercise-fun I get "Couldn't satisfy such-that predicate after 100 tries.", I assume because the generator does not try to generate keywords for x
and y
that are in m
. Is there a way to do this with a custom generator? I couldn't figure out how to feed the incoming m
to with-gen
so it knows that keys to generate.you can do this with a custom generator using gen/fmap
first generate a tuple of x, int, y, int, then fmap to make a vector containing a map of that stuff, plus x and y
the spec guide has some fmap examples https://clojure.org/guides/spec
by wrapping the first s/and
with s/with-gen
it is possible to generate the whole argument list at once as a vector?
i’ve got an httpkit server running with compojure, and one route leads to a websocket handler
your hanging might be because you are trying to keep running without letting the handler return
I got an API that uses timbre for logging. I log various things throughout the request life-cycle. There are some logs that don't include some useful bits of information that I would like to add to the logs. But I am not liking the idea of having to refactor code to pass through information that will ultimately be only be used for logging. Is it possible to set up the logger with a context on a per request basis? So that for each log during that request it logs some basic information associated with that request. There appears to be a function called with-context
but not sure if thats exactly what I want
you have to return from your wshandler, the return value is the result of the as-channel function
if ws-handler is something like (defn ws-handler [req] (while true (println "loop forever")) ...)
then you would get a hang
Any tips on REPL-driven development in VSCode, preferably using Boot? The appeal to me of Boot is that I can make single-file programs, without needing any directory structure and while specifying my dependencies in my program. I’ve only written very small Clojure programs so far.
I’ve tried using Calva but haven’t figured out how to “jack in”. So for now my code and my REPL have not been connected.
Conversely, is it possible to specify dependencies within my program and without putting my code in a src
directory when using Clojure CLI?
@ruyvalle With Calva you can start your boot repl in some terminal (VS Code's terminal views work fine) and then use Connect instead of Jack in. If you use the project type Generic you should get away without needing any directory structure or anything like that.
@ruyvalle Yes, src
is just a convention -- the default value of :paths
is ["src"]
but you can specify that to include other directories, including "."
if you want.
You can also just say clojure script.clj
to run a Clojure script in the current directory:
(! 820)-> ls -l
total 8
-rw-r--r-- 1 sean staff 19 Jul 7 16:02 hello.clj
(! 821)-> cat hello.clj
(println "Hello!")
(! 822)-> clojure hello.clj
Hello!
(! 823)->
If you're on Linux/macOS, you can also do this:
(! 826)-> cat bin/time.sh
#!/usr/bin/env clojure -Sdeps {:deps,{clj-time,{:mvn/version,"0.14.2"}}}
(require '[clj-time.core :as t])
(println (str "Time is now " (t/now)))
(println (str "Java version is " (System/getProperty "java.version")))
(! 827)-> bin/time.sh
Time is now 2020-07-07T23:03:46.105Z
Java version is 14
I guess I was doing something wrong a few days ago, because I definitely tried clojure script.clj
I have tried writing a custom generator for my earlier spec problem but I am running into the same problem - the generator still cannot meet the spec
(s/def ::key-int-map (s/and (s/map-of keyword? integer?)))
(defn lowest-val
"Given two keys x and y, returns the key with the lowest associated value in
m. Returns nil if the values are =."
[m x y]
(let [m (select-keys m [x y])]
(case (compare (-> m first val) (-> m second val))
-1 (-> m first key)
0 nil
1 (-> m second key))))
(s/fdef lowest-val
:args (s/with-gen (s/and (s/cat :m (s/map-of keyword? integer?) :x keyword? :y keyword?)
#(contains? (:m %) (:x %))
#(contains? (:m %) (:y %)))
(fn [] gen/fmap
#(let [s (seq %)]
[% (-> s rand-nth key) (-> s rand-nth key)])
(s/gen ::key-int-map)))
:ret any?)
I assume I am doing something wrong when it comes to generating the whole argument list together, but I am not sure what 😕
I suspect that code would be easier to work on if the (s/with-gen ...)
were pulled into its own def or s/def, similarly with the fn that should return the generator
and as I looked closer to enumerate the things that needed abstracting out, I see this:
> (fn [] gen/fmap #(...) (s/gen ...))
that takes no args, discards gen/fmap (doing nothing with it), discards an anonymous function (doing nothing with it) and finally returns the s/gen that didn' twork in the first place
which is surely your bug
but back to the original point, things like that are easier to see when you don't throw so much nesting into one form
especially anonymous functions that aren't closing over locals, can be moved into proper functions
yeah I have a bad habit of writing big forms and then only pulling them apart once they work
that gen was in a seperate form but I couldn't quite get it wrapped in a function correctly
Strangely I tend to go the other way - I like to “name” every little discrete step in my logic (by putting it in its own fn), then afterwards I look for all the silly little “don’t add any value” fns and move them inline. 😉
But then I have a terrible memory, so have trouble holding large blocks of logic, and how the data changes “shape” through it, in my head.