Fork me on GitHub
#beginners
<
2020-04-16
>
alidlorenzo01:04:27

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 `{[email protected](reduce (fn [acc k] (conj acc (keyword k) k))
                                  []
                                  syms)
                        ;; extra splice to prevent "uneven pairs" compile error.
                        [email protected][]}
                     m)))

Cameron02:04:22

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))

Cameron02:04:37

(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)

dpsutton02:04:40

the [email protected][] works around a quirk in the reader and I would problably do (merge (into {} ~(reduce`

dpsutton02:04:34

I like your macro and I've wanted one like it for a while

dpsutton02:04:30

and i bet your version will error on the following: (dmap [x x] {})

alidlorenzo02:04:39

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 ๐Ÿ™‚

dpsutton02:04:41

the into version will just overwrite

alidlorenzo02:04:38

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}

alidlorenzo02:04:14

oh wait thatโ€™s with the old version, havenโ€™t rewritten it with into

dpsutton02:04:39

oh i expected the version that made a literal map to explode with duplicate keys

dpsutton02:04:57

yeah i thought this would blow up {[email protected][:a :d :a :c] [email protected][]} but the fact that the [email protected][] is present kinda gives away the reason it doesn't blow up

alidlorenzo02:04:16

why did you think above would blow up?

alidlorenzo02:04:03

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))))

alidlorenzo02:04:10

thanks again guys

dpsutton02:04:24

the reader does some checks on map literals as you've already seenwith the [email protected][] 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

jeff tang03:04:21

#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

seancorfield04:04:32

I think @U051BLM8F said that the next version of lein would bundle nREPL 0.7 since that's only just been released?

seancorfield04:04:30

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."

jeff tang10:04:39

thank you @U04V70XH6 ๐Ÿ™‚

seancorfield04:04:12

@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.

alidlorenzo04:04:37

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

seancorfield04:04:49

There are usage examples in the comment below. LMK if you have any questions about it.

noisesmith15:04:22

to be clear it's not just let bindings - it's all locals including loop, for, let, fn ...

noisesmith15:04:43

it even captures the weirdly named tmp names that destructuring creates but doesn' tusually expose

seancorfield17:04:12

(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!)

Uri10:04:39

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?

refset10:04:39

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 ๐Ÿ™‚

Uri10:04:47

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?

Uri10:04:54

you know what let me ask there for others' benefit

refset10:04:56

> 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

introom12:04:41

is there a sorted multi set ?

andy.fingerhut13:04:28

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.

Mitch13:04:32

I would use a sorted map with the count as the vals

andy.fingerhut13:04:19

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.

Mitch13:04:31

Vectors give you everything that multisets do afaik

Mitch13:04:34

when would I want to use *command-line-args* rather than just parsing the args from my main function?

alexmiller13:04:53

there is no reason. command-line-args is useful if you are running as a script, not from a main function

alexmiller13:04:19

that is, clj foo.clj vs clj -m foo.clj

jsn13:04:00

vectors don't give you e.g. fast membership check

Mitch13:04:27

isn't it a hash tree?

Mitch13:04:31

ah thanks

alexmiller13:04:33

not hashed on value that is

alexmiller13:04:43

vectors give you fast lookup by index

Aviv Kotek14:04:12

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?

hindol15:04:04

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.

Aviv Kotek15:04:16

awesome. would there any way to reduce all those reduce operations?

hindol15:04:56

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]))

hindol15:04:59

Next task will be to assoc words in each group.

Aviv Kotek15:04:27

this becomes harder than the imperative solutions, i'll give it a try

hindol15:04:53

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"])

Aviv Kotek12:04:54

@UJRDALZA5, some further implementations have performed on Zulip (#data-science) if you are curious about final results, nicely done imo.

hindol12:04:11

Zulip UI is a mess. Can you share a direct link? Don't know if Zulip allows it.

Aviv Kotek12:04:49

joinr, jack rushner last comments will do.

hindol13:04:59

The last one is neat!

hindol13:04:15

And quite readable too.

Aviv Kotek13:04:36

yep, really nice

Aviv Kotek14:04:41

interested in better practices for vectorized /matrix programming with functional & clojure, :)

teodorlu13:04:44

If I were to use matrices in Clojure, I'd start with `http://tech.ml.dataset` tech.datatype: https://github.com/techascent/tech.datatype

Aviv Kotek09:04:59

why should use that and not core.matrix / nehandethral ?

teodorlu16:04:36

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

Aviv Kotek18:04:45

i'll give it a look (already invested in that core.matrix :\\ )

teodorlu19:04:54

Hope it works out for you ๐Ÿ™‚

ashnur16:04:32

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.

ashnur16:04:45

What is the best way to do this?

didibus16:04:25

Probably using Spec, or some of the other similar libs like Schema or Mali

ashnur16:04:02

well, spec of course is out of the question ๐Ÿ™‚

noisesmith16:04:11

why is it out of the question? your "of course" is a non sequitor to me

Darin Douglass16:04:50

spec (or other lib) seems like the exact fit for this ยฏ\(ใƒ„)/ยฏ

ashnur17:04:22

because spec is not for this

ashnur17:04:38

spec is for the developer to check if their code is ok, not for user data to be validated

ashnur17:04:58

I am happy to be corrected on this!

noisesmith17:04:09

spec is for validation as well, last I checked - see for example s/conform

noisesmith17:04:45

https://clojure.org/guides/spec#_using_spec_for_validation - spec for validation is a heading in the official guide :D

ashnur17:04:45

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 ๐Ÿ˜ž

Darin Douglass17:04:09

what channels? i'd be interested to see their reasoning

Darin Douglass17:04:34

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

noisesmith17:04:42

anyway, my understanding was this use case is why s/valid? and s/conform are provided

ashnur17:04:57

thanks for the link, I am reading it now

ashnur17:04:06

also, first time I heard this was in this video https://youtu.be/Xb0UhDeHzBM at 43:31

ashnur17:04:23

the slide also says 'no runtime checking!'

didibus17:04:02

It does runtime validation

ashnur17:04:18

ok, i am happy to be corrected. i will use it ๐Ÿ™‚

didibus17:04:17

For runtime validation you want to use s/valid? . And for development you want to use instrument.

didibus17:04:46

It's quite a multi-purpose system, so you need to pay good attention.of what context people are talking of it

didibus17:04:06

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

didibus17:04:33

And then you can also use it for generative testing, for mocking, etc.

alexmiller17:04:59

it is perfectly valid to use spec at runtime to validate data. it is not recommended to instrument functions at runtime

alexmiller17:04:35

for runtime use, s/valid? or s/explain are probably the best api functions to use, and maybe secondarily s/conform

seancorfield17:04:40

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/

ashnur16:04:09

will check the others

amarus20:04:02

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 now

jtth21:04:56

is the recommended library for accessing firebase via clojure (on the jvm)? or should i just hit the REST API with clj-http or something?

kwrooijen22:04:37

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

v21:04:24

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;
};

v21:04:24

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;
};

Shako Farhad22:04:10

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). ๐Ÿ˜ฎ

v22:04:30

I am trying to re-order a list

v22:04:21

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]

didibus22:04:43

ClojureScript vectors are immutable, you can't transform them in-place

Shako Farhad23:04:56

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. ๐Ÿ™‚

v23:04:09

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))))

didibus00:04:08

But what's the goal?

didibus00:04:53

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))))

v00:04:34

@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 ๐Ÿ™‚

didibus00:04:17

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

didibus00:04:47

I don't know if that matters or not to you

didibus00:04:40

subvec is O(1), but concat to put them back together is O(n), so it doesn't gain you anything.

didibus00:04:40

Oh oups, I'm a big dummy, and completly forgot

didibus00:04:45

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]

didibus00:04:39

This is going to be O(1)

didibus00:04:54

You need a vector though, doesn't work on list or sequence

aisamu01:04:11

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)))

v02:04:59

I am sorry but thats not how the function is supposed to work!

v02:04:05

@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]

didibus02:04:52

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 ?

Shako Farhad08:04:36

@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.

Shako Farhad08:04:26

[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

v12:04:30

@U0K064KQV here is a visual representation of what I am trying to do

Shako Farhad12:04:56

Why doesn't the swap function above not work? It swaps two indexes. That is all you need right? ๐Ÿ˜ฎ

v12:04:04

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

v13:04:11

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)))))

Shako Farhad13:04:56

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. ๐Ÿ˜ฎ

v13:04:00

@U0121V7FXG8 I tried using the function above, it doesnt work!

v13:04:16

Again I am not trying to swap two indexes!

didibus17:04:35

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?

didibus17:04:28

Oh..., Nevermind ok, I got it

didibus17:04:05

You're just loving an element to a different position, not swapping ok makes sense. I don't know why it took me longer

Shako Farhad17:04:59

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

didibus18:04:51

Ya, that's probably the best way to implement the algorithm, to just walk from start to end and swap along the way.

didibus18:04:42

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

Shako Farhad18:04:54

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. ๐Ÿ˜„

didibus18:04:22

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 ๐Ÿ˜

aisamu15:04:46

@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)))))

Steven Katz14:04:13

Stolen froma solution to the 4clojure item 44:

(fn [n coll]
  (take (count coll) (drop (mod n (count coll)) (cycle coll))))

Steven Katz14:04:09

n is the number of places to rotate, also works with negative: credit to: https://gist.github.com/SegFaultAX/3607101

Mario C.23:04:03

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 ?

Mario C.23:04:34

assuming that returning a nil value is a valid return type

Mario C.23:04:56

I think I am going to just check argument type since a nil parameter will be common

alidlorenzo23:04:36

nil is also returned by default so you can check that a value does exist, i.e. (when (some? x) ..) before running your operation

phronmophobic23:04:21

you can also check out fnil, although I prefer alidloโ€™s suggestion

Mario C.23:04:57

Thanks guys! Yes ive been trying to find uses for fnil since it looks handy but I always default to the when check

hindol12:04:49

Think you can drop the some? too. (when x ...)

Jorge Tovar23:04:31

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]

noisesmith23:04:44

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)

noisesmith23:04:26

many people disagree with choices provided by luminus but nothing else is as full featured in a new project template

Jorge Tovar00:04:50

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

introom07:04:13

@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.

hindol08:04:33

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/.