This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-16
Channels
- # announcements (1)
- # babashka (23)
- # beginners (157)
- # boot (3)
- # calva (2)
- # chlorine-clover (12)
- # cider (14)
- # clara (5)
- # clj-kondo (6)
- # cljs-dev (61)
- # cljsrn (30)
- # clojure (65)
- # clojure-argentina (8)
- # clojure-berlin (2)
- # clojure-europe (13)
- # clojure-france (9)
- # clojure-germany (2)
- # clojure-italy (4)
- # clojure-nl (6)
- # clojure-portugal (2)
- # clojure-romania (2)
- # clojure-uk (76)
- # clojurescript (56)
- # conjure (52)
- # core-async (37)
- # datomic (209)
- # duct (17)
- # emacs (17)
- # exercism (1)
- # fulcro (26)
- # graalvm (5)
- # instaparse (2)
- # jackdaw (9)
- # jobs-discuss (27)
- # joker (2)
- # juxt (23)
- # leiningen (4)
- # malli (11)
- # midje (3)
- # pedestal (2)
- # quil (2)
- # re-frame (78)
- # reagent (8)
- # reitit (18)
- # remote-jobs (1)
- # ring (2)
- # ring-swagger (1)
- # shadow-cljs (29)
- # sql (11)
- # test-check (12)
- # tools-deps (5)
- # xtdb (16)
- # yada (4)
giving a shot at my first macro 😎 I’ve grown to like JS’s destructuring syntax so I’m writing a macro that gives me something similar. below i’m converting symbols into key-value pairs in a map. Looks like a single splice inside a map returns a compile error bc it assumes it’s an uneven pair. Is it OK to just add an extra splice like I did below?
(defmacro dmap
"Constructs map of destrusctured symbols `syms` and an optional map `m`.
e.g. (def x 1) (dmap [x] {:y 2}) -> {:x 1 :y 2}"
([syms] `(dmap ~syms {}))
([syms m]
`(identity ~(merge `{~@(reduce (fn [acc k] (conj acc (keyword k) k))
[]
syms)
;; extra splice to prevent "uneven pairs" compile error.
~@[]}
m)))
I dunno, that does seem a little hackey, I think in this sort of scenario I usually just see something like this
(into {} (reduce (fn [acc k] (conj acc [(keyword k) k]))
[]
syms))
(also note that in this case, instead of (conj acc (keyword k) k)
you'd have (conj acc *[*(keyword k) k*]*)
, since that's easy to miss from a glance)
the ~@[]
works around a quirk in the reader and I would problably do (merge (into {} ~(reduce`
that’s a good alternative, thanks @zdot101
and thanks @dpsutton *, disliked having to read lots of {:foo foo}
declarations and gave me a good excuse to write a macro 🙂
hm that’s a good edge case, what would you except result to be? right now if x is 1 (dmap [x x] {})
returns {:x 1}
yeah i thought this would blow up {~@[:a :d :a :c] ~@[]}
but the fact that the ~@[] is present kinda gives away the reason it doesn't blow up
dmap
version to is out 😜
(defmacro dmap
"Constructs map of destrusctured symbols `syms` and an optional map `m`.
e.g. (def x 1) (dmap [x] {:y 2}) -> {:x 1 :y 2}"
([syms] `(dmap ~syms {}))
([syms m]
`(identity ~(merge (into {} (reduce (fn [acc k] (conj acc [(keyword k) k]))
[]
syms))
m))))
the reader does some checks on map literals as you've already seenwith the ~@[]
to ensure there were two elements. you can see duplicate keys check with
cljs.user=> {:x 1 :x 2}
Syntax error reading source at (<cljs repl>:1).
Map literal contains duplicate key: :x
#leiningen question: when I run lein repl
, I have nREPL 0.6
, REPL-y 0.4.4
, but nREPL should be updated to 0.7
, no? I have lein v 2.9.3
and OpenJDK 11.0.2
I think @U051BLM8F said that the next version of lein
would bundle nREPL 0.7 since that's only just been released?
Yeah, here https://metaredux.com/posts/2020/04/10/a-cornucopia-of-nrepl-updates.html under Misc "The next Leiningen release will bundle nREPL 0.7."
thank you @U04V70XH6 🙂
@alidcastano You might also look at https://github.com/worldsingles/commons/blob/master/src/ws/clojure/extensions.clj#L148 for inspiration. It's based on a macro I saw @noisesmith post and also intended to return boilerplate when creating hash maps from local bindings.
interesting, that’s a much more complex utility.
looks like it somehow accesses the let bindings and selectively includes them based on op
keyword.
will try and learn from it thanks
There are usage examples in the comment
below. LMK if you have any questions about it.
to be clear it's not just let bindings - it's all locals including loop, for, let, fn ...
it even captures the weirdly named tmp names that destructuring creates but doesn' tusually expose
(and I carefully did not say "`let` bindings" in that local-map
stuff but it would probably be clearer if I showed what the results are inline in the comment
at the bottom of the file -- and added a destructuring example too!)
Hi, thinking about using datomic/crux and wanted to ask some questions if anyone is knowledgeable about either. 1. Can I version a bunch of datoms, and then invalidate them all at once? 2. How would storing objects look like from javascript/python using http? 3. How would querying be done from javascript/python?
Hi @U011WV5VD0V - I work on Crux. A Crux document can definitely be thought of as equivalent to a "bunch of datoms" that get versioned and invalidated together. Storing and querying data over HTTP is supported: https://www.opencrux.com/docs#restapi
HTTP only talks application/json
right now though, so you would probably want to convert json<->edn yourself by shelling out to babashka or similar, until we implement official application/json
support.
Feel free to ask for help on #crux 🙂
Thanks!
Didn't know this channel exists, will ask there next time 🙂
So if I'm loading a bunch of entities like so
[{age: 40, name: "john"}, ...]
they get converted to datoms indexed etc'
and I can tomorrow load a new batch and invalidate the previous one.
Great.
My other question is about setting crux up in a kubernetes cluster - is there a tutorial I can follow somewhere?
> So if I'm loading a bunch of entities like so
> [{age: 40, name: "john"}, ...]
they get converted to datoms indexed etc'
> and I can tomorrow load a new batch and invalidate the previous one.
> Great.
That's pretty much it. A document is a version of an entity (so you also need to specify and ID), and the indexes are datom-like
There is no multi-set data structure built into Clojure, unless you want to think of a map from the set elements to integers that are the count of the number of times the element appears in the set as a kind of multi-set.
I would use a sorted map with the count as the vals
I would not be surprised if there is some 3rd party library somewhere for implementing a multi-set, but I don't recall a particular one off the top of my head.
Vectors give you everything that multisets do afaik
when would I want to use *command-line-args*
rather than just parsing the args from my main function?
there is no reason. command-line-args is useful if you are running as a script, not from a main function
isn't it a hash tree?
not hashed
ah thanks
not hashed on value that is
vectors give you fast lookup by index
i'm trying to build a co-occurence matrix of given documents and window-size,
this matrix will represent the context
(it n subsequent AND preceding tokens)
of a token in the text.
"Roses are red sky is blue"
with windows size=2, would map roses: [are, red]. are: [Roses, red, sky]. etc...
then this will go into a matrix. tokens will represent row/col
in the matrix (term-to-term matrix).
I have made it fairly easy https://stackoverflow.com/questions/35562789/how-do-i-calculate-a-word-word-co-occurrence-matrix-with-sklearn/61246990#61246990 with numpy
and nested-loops updating the matrix, but somehow my https://github.com/akotek/vicarious/blob/master/src/vicarious/word2vec.clj seems to have big LOC, less readable and was more difficult to implement. I have used core.matrix
so for the string example with n=1:
(co-occurrence-matrix [["roses" "are" "red" "sky" "is" "blue"]] 1)
=>
{:M [[0.0 0.0 0.0 1.0 1.0 0.0]
[0.0 0.0 1.0 0.0 0.0 0.0]
[0.0 1.0 0.0 0.0 0.0 1.0]
[1.0 0.0 0.0 0.0 0.0 1.0]
[1.0 0.0 0.0 0.0 0.0 0.0]
[0.0 0.0 1.0 1.0 0.0 0.0]],
:word2idx {"are" 0, "blue" 1, "is" 2, "red" 3, "roses" 4, "sky" 5}}
are there better ways to iterate over the text and transform the data? is my usage of matrix operations correct? is there's any better practices for vectorized-programming with functional programming?
I looked at the Python solution. You can achieve something similar with map-indexed
.
(map-indexed vector ["roses" "are" "red" "sky" "is" "blue"])
;; => ([0 "roses"] [1 "are"] [2 "red"] [3 "sky"] [4 "is"] [5 "blue"])
Once you have the indices next to the words, you can have a similar algorithm as Python.awesome. would there any way to reduce all those reduce
operations?
I was trying it out in a REPL and I reached here,
(let [n 2
words ["roses" "are" "red" "sky" "is" "blue"]]
(take (count words)
(partition (inc n) 1
(concat (map-indexed vector words)
(repeat [nil nil])))))
;; => (([0 "roses"] [1 "are"] [2 "red"])
([1 "are"] [2 "red"] [3 "sky"])
([2 "red"] [3 "sky"] [4 "is"])
([3 "sky"] [4 "is"] [5 "blue"])
([4 "is"] [5 "blue"] [nil nil])
([5 "blue"] [nil nil] [nil nil]))
this becomes harder than the imperative solutions, i'll give it a try
for
is a Swiss army knife.
(let [n 2
words ["roses" "are" "red" "sky" "is" "blue"]
groups (take (count words)
(partition (inc n) 1
(concat (map-indexed vector words)
(repeat [nil nil]))))]
(for [group groups
[ix x] group
[iy y] group
:when (and ix iy (< ix iy))]
[x y]))
;; =>
(["roses" "are"]
["roses" "red"]
["are" "red"]
["are" "red"]
["are" "sky"]
["red" "sky"]
["red" "sky"]
["red" "is"]
["sky" "is"]
["sky" "is"]
["sky" "blue"]
["is" "blue"]
["is" "blue"])
@UJRDALZA5, some further implementations have performed on Zulip (#data-science) if you are curious about final results, nicely done imo.
joinr, jack rushner last comments will do.
yep, really nice
interested in better practices for vectorized /matrix programming with functional & clojure, :)
If I were to use matrices in Clojure, I'd start with `http://tech.ml.dataset` tech.datatype
:
https://github.com/techascent/tech.datatype
why should use that and not core.matrix / nehandethral ?
I don't think core.matrix has seen much love lately. About Neanderthal/tech.datatype, I think it comes to more preferece. I tried Neanderthal first, and wasn't 100 % happy with the docs. With tech.datatype, I've been thoroughly impressed with @UDRJMEFSN's work. The results he produces, how he documents his work, his design and how he engages with the community. He is super active over at https://clojurians.zulipchat.com/#narrow/stream/151924-data-science
awesome
i'll give it a look (already invested in that core.matrix :\\ )
I have a set of keys and for each key another unique set of keys, for this second nested level, I would like to be able to encode information on the shape of the data it can take if the key appears in a map. So for example {:other {:fields #{:other_description}}
and I need to say about :other_description
that it is string and it needs to be minimum this length, maximum that length.
why is it out of the question? your "of course" is a non sequitor to me
spec (or other lib) seems like the exact fit for this ¯\(ツ)/¯
spec is for the developer to check if their code is ok, not for user data to be validated
spec is for validation as well, last I checked - see for example s/conform
https://clojure.org/guides/spec#_using_spec_for_validation - spec for validation is a heading in the official guide :D
I know but I have several people telling me right now on other channels that it's not appropriate to run spec elsewhere than in a development environment. Confusing 😞
what channels? i'd be interested to see their reasoning
spec is just a way to define how data should be structured. you can use that in whatever ways you'd like: dev ergonomics, data validation, etc
anyway, my understanding was this use case is why s/valid?
and s/conform
are provided
also, first time I heard this was in this video https://youtu.be/Xb0UhDeHzBM at 43:31
For runtime validation you want to use s/valid? . And for development you want to use instrument.
It's quite a multi-purpose system, so you need to pay good attention.of what context people are talking of it
Cause you can use it to spec your functions and instrument them so they are checked for mismatch at development time. But you can also spec your user input/output and validate them at run-time to protect yourself from bad input and report errors back to the user
it is perfectly valid to use spec at runtime to validate data. it is not recommended to instrument functions at runtime
for runtime use, s/valid? or s/explain are probably the best api functions to use, and maybe secondarily s/conform
If it helps, this blog post talks about all the different ways we use Spec in dev, test, and production: https://corfield.org/blog/2019/09/13/using-spec/
If it helps, this blog post talks about all the different ways we use Spec in dev, test, and production: https://corfield.org/blog/2019/09/13/using-spec/
Hello, guys! I'm new in clojure world and I'm creating simple API service with compojure-api lib. I'm writing schema for validation and don't understand how to validate and coerce date in my model. Can you help?
(ns hs-crud.patient
(:require [schema.core :as s])
;; code for validators
(s/defschema Patient
{:fullname (s/constrained s/Str valid-fullname?)
:gender (s/enum :male :female :other)
:birthdate s/Str ;; todo add date validator
:address (s/constrained s/Str valid-address?)
:rpn (s/constrained s/Str valid-rpn?)})
That is how my schema looks nowis the recommended library for accessing firebase via clojure (on the jvm)? or should i just hit the REST API with clj-http or something?
Maybe something like this? https://github.com/alekcz/charmander I'm not really familiar with Firebase. I just happened to watch this talk of the author https://www.youtube.com/watch?v=j57UbYFbI-U He also made some more libraries to target Firebase
Hello I am trying to convert this function to cljs so far I am unable to do it. Can someone help me 🙂
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
What are you trying to do here? I am not familiar with splice etc. If you just want to shuffle the list then just use (shuffle some-list). 😮
I am trying to re-order a list
so for example lets say i have a vector [1,2,3,4,5] and i want to move 0th index to 2nd index, the function should transform the vector like so [2,3,1,4,5]
Yes, but it is possible to create a function that will create a new list with the elements swapped and return that. You could also create an atom if you want this list to be shared globally (not recommended). Please check this function out: https://clojuredocs.org/clojure.core/split-at I think that is what you are looking for. You split the vector at the given indices, then you rebuild a new vector by using cons, conj, pop etc and return that. Immutability is preserved, you got your function. 🙂
I was able to come up with a very hacky solution
(defn vec-remove
"remove elem in coll"
[pos coll]
(vec (concat (subvec coll 0 pos) (subvec coll (inc pos)))))
(defn re-order!
"Re-orders the vector"
[vect sourceIndex destinationIndex]
(if (= sourceIndex destinationIndex)
vect
(let [moving-item (get vect sourceIndex)
new-coll (vec-remove sourceIndex vect)
[colA colB] (split-at destinationIndex new-coll)]
(-> (vec colA)
(conj moving-item)
(concat (vec colB))
vec))))
For example you could just do
(defn swap [coll a b]
(let [av (get coll a)
bv (get coll b)]
(into []
(map-indexed
(fn[i e]
(cond
(= i a)
bv
(= i b)
av
:else
e))
coll))))
@U0K064KQV I am implementing beautidul react drag and drop in reagent 🙂 Here is the example https://codesandbox.io/s/k260nyxq9v?file=/index.js:373-568. The re order function is resonsible for re ordering items in the list 🙂
Hum, so I mean, you can use my function, but as you see, anything based on a vector will require O(n) time to re-order elements
subvec is O(1), but concat to put them back together is O(n), so it doesn't gain you anything.
You can just do:
(defn swap [v a b]
(let [av (get v a)
bv (get v b)]
(-> v
(assoc b av)
(assoc a bv))))
user=> (swap [1 2 3 4 5 6] 0 3)
[4 2 3 1 5 6]
Just for some silly golf (`v` is never changed, assoc
takes multiple parameters)
(defn swap [v a b]
(assoc v
b (get v a)
a (get v b)))
I am sorry but thats not how the function is supposed to work!
@U1UQEM078 @U0K064KQV (swap [1 2 3 4 5 6] 0 3) should return [2 3 4 1 5 6] not [4 2 3 1 5 6]
oh, ok, I didn't understand what your function does then. Not sure I'm following the logic. It moves start exclusive to end inclusive at the front ?
@U0K064KQV, in clojrescript a vector is actually just a map where the indices are the keys. So that is what he is abusing here. With assoc function you can associate several items at once. So basically he says, take the v vector, associate b index with what is at a position and associate a index with what is at b position. Since v is immutable, we can do this. The return value from assoc is not a changed v vector, but rather just a new one that has these values swapped.
[1 2 3] vector is the same as {:1 1 :2 2 :3 3} in clojure. That is why assoc, which usually takes a map, keys and values as arguments, can take a vector and its indexes
@U0K064KQV here is a visual representation of what I am trying to do
Why doesn't the swap function above not work? It swaps two indexes. That is all you need right? 😮
It works for the item thats next to it i,e moving item from index 1 to index 2. But what if you had to move from index 4 to 0, Then the items where originally in index 0, 1, 2, 3, 4.. now lives in 1, 2, 3, 4 and 0 respectively
So this is the final solution i came up with
(defn drop-index [col idx]
(into [] (filter identity (map-indexed #(if (not= %1 idx) %2) col))))
(defn re-order
[list start-index new-index]
(let [moved-item (get list start-index)
remaining-items (drop-index list start-index)]
(into []
(concat
(conj (subvec remaining-items 0 new-index) moved-item)
(subvec remaining-items new-index)))))
I would just use the swap function above because that one can swap any two indexes. Doesnt need to be next to one another. If your list is saved in a DB or just is an atom then you just swap two items everytime something is dragged and dropped into place, and update the list. To me this doesn't need anything fancy other than assoc. 😮
@U0121V7FXG8 I tried using the function above, it doesnt work!
Again I am not trying to swap two indexes!
Ya, I don't understand why swap doesn't work, you're just swapping the position of two items by moving it. Unless you're trying to add a new element in the middle or remove an existing one?
You're just loving an element to a different position, not swapping ok makes sense. I don't know why it took me longer
But isn't he really swapping? Everytime the element is being moved up or down, it is being swapped with the closest element, and then if he moves it further it gets swapped with the next closest element. [1 2 3 4] (move 2 to 4) -> [1 3 2 4] -> [1 3 4 2]. Here you can see that 2 was swapped with 3, then again with 4. :x
Ya, that's probably the best way to implement the algorithm, to just walk from start to end and swap along the way.
But you need to add that walking swap logic, right now my swap was just swapping two things, not doing the rolling swap you described
But the rolling swap can be done with an atom. Or it can be done recursively. You just give it how many times it should move to the left or right, and it calls itself that many times. Something like that. 😄
Ya, I'd probably do it recursively. I mean it can be done, would probably take me a few minutes to put it together and get it working properly 😝
@UGMEQUCTV you can use the same approach for drop-index
as well:
(defn drop-index [items index]
(vec (concat (subvec items 0 index) (subvec items (inc index)))))
Stolen froma solution to the 4clojure item 44:
(fn [n coll]
(take (count coll) (drop (mod n (count coll)) (cycle coll))))
n is the number of places to rotate, also works with negative: credit to: https://gist.github.com/SegFaultAX/3607101
If you have a function that takes in a string and does an operation on it but given a nil value, throws an exception. Is the preferred way to wrap the operations in a try-catch or to just check if the argument is a string and return nil ?
nil is also returned by default so you can check that a value does exist, i.e. (when (some? x) ..)
before running your operation
you can also check out fnil
, although I prefer alidlo’s suggestion
Thanks guys! Yes ive been trying to find uses for fnil since it looks handy but I always default to the when
check
Hi! Im currently working in a big project in a Colombian Bank to make a digital and cloud native application (=~Greenfield), currently our stack is Java . AWS DynamoDB , SQS, ECS Docker, HTTP integrations with retrofit and CircleCI ❤️. They gave me the opportunity to suggest another tech stack (We have some bugs and some performance problems, too verbose) . Im currently reading Clojure for the brave and `I want to know what are all the components like Datomic DB, Leiningen, ETC to make CRUD microservices , with tokens security that can make HTTP request? I have to make a POC` . [Two colleagues will make the same exercise with Scala and Elixit but I think with my little knowledge that clojure is the best choice]
your fastest startup is probably lein with the luminus template, which makes a bunch of opinionated choices bout libraries for a reset server stack (with optional cljs frontend)
many people disagree with choices provided by luminus but nothing else is as full featured in a new project template
The microservices are restful we have a mobile application. I woukd like to see some articles and examples to move to the cloud like nubank
@U010T62KHEE first step is to learn about datomic https://www.youtube.com/playlist?list=PLZdCLR02grLoMy4TXE4DZYIuxs3Q9uc4i
@UGMEQUCTV why suggest datomic? the added benefits is often not a necessity. dynamodb itself is enough. adding a datomic layer hurts the performance of dynamo and adds point of failure.
IMO learning Clojure and Datomic at the same time might be challenging. From your comment, it seems you are writing just the ReST API bits and not a frontend. I think https://github.com/ring-clojure/ring is the easiest. Ring is a spec and there are many libraries that conform to this spec. The https://github.com/sunng87/ring-jetty9-adapter can embed the Jetty webserver in the JAR itself. As for the API bits, there are many many options but you can check out http://clojure-liberator.github.io/liberator/.