This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-03-20
Channels
- # admin-announcements (1)
- # announcements (9)
- # aws (11)
- # babashka (33)
- # beginners (125)
- # calva (20)
- # cider (18)
- # clj-kondo (7)
- # cljs-dev (73)
- # clojure (72)
- # clojure-europe (18)
- # clojure-italy (13)
- # clojure-nl (13)
- # clojure-uk (9)
- # clojurescript (22)
- # core-async (7)
- # cursive (1)
- # data-science (25)
- # datomic (22)
- # duct (32)
- # emacs (13)
- # graalvm (5)
- # hoplon (16)
- # juxt (6)
- # kaocha (8)
- # leiningen (3)
- # malli (11)
- # meander (12)
- # off-topic (18)
- # pathom (109)
- # pedestal (5)
- # rdf (10)
- # reagent (1)
- # reitit (12)
- # shadow-cljs (27)
- # spacemacs (5)
- # sql (9)
- # tools-deps (7)
I am saving a map into a JSONB postgres column but was having issues with cheshire so decided to use clojure.data.json
since the custom encoder/decoder seemed a bit more straight forward. What is wrong with this solution?
(def opt_data {:sheet-data-structure
{"RD" {[1 4] {:backgroundColor "#0000"}
:skip #{nil [5 5] [6 6]}}
"Model" {:mods {[3 4] {:borderRight "none"}}
:test [1 2 3]}
"Tax" {[99 9] ":should-not-be-keyword"}}})
(defn value-serializer
[_ v]
(cond
(= (type v)
(type #{})) (str "#SET~" v)
:else v))
(defn value-deserializer
[_ v]
(cond
(str/starts-with? v "#SET~") (-> (subs v 5) read-string set)
:else v))
(defn keys-serializer
[k]
(cond
(keyword? k) (str "#KEYWORD~" k)
(vector? k) (str "#VECTOR~" k)
:else k))
(defn keys-deserializer
[k]
(cond
(str/starts-with? k "#KEYWORD~") (-> k (subs 10) keyword)
(str/starts-with? k "#VECTOR~") (-> k (subs 8read-string)
:else k))
(-> (json/write-str opt_data :value-fn value-serializer :key-fn keys-serializer)
(json/read-str :value-fn value-deserializer :key-fn keys-deserializer))
The reason I am doing this is that I need to keep sets as sets and vector keys as vectors and not strings. This data I am reading from the DB is being merged in with other another data of the same structure.
(-> k (subs 8read-string)
is obviously wrong - looks like a ) (
got eatenand replaced with 8
I'd use
I'd use pr-str on the k in the serializer, because it can preserve things that str might notpr-str
instead of str inside the serializer
(cmd)user=> (str (map inc [1 2 3]))
"clojure.lang.LazySeq@7c42"
(cmd)user=> (pr-str (map inc [1 2 3]))
"(2 3 4)"
it's a common gotcha - a good rule of thumb is that if what you want is the string you'd see in the repl for a given object, you want pr-str
and not str
Is this a bad approach though? Is there a better way of doing this that I am not seeing?
There is discussion tomorrow about whether to do this manually or using Transit. Personally I would rather use Transit since it works out of the box and can probably do the job faster
what transit creates when you ask for "json" is not as likely to be useful in a jsonb field (eg. its shorthand for backreference of repeated keys in one document)
but it definitely works and its tagged readers/writers are mature and tested unlike yours
I got stuck with a problem. Could someone help? I would like to call a -main
function from a clojure script file with a namespace, but I do not know to do that. Here is what I tried. I have a Code.clj
with Code
namespace and a -main
function. My current dir is the same directory as the source code (`/tmp/test`)
$ pwd
/tmp/test
$ cat Code.clj
(ns Code
(:gen-class))
(defn -main []
(println "hello world"))
$ clojure -m Code Code.clj
Execution error (FileNotFoundException) at clojure.main/main (main.java:40).
Could not locate Code__init.class, Code.clj or Code.cljc on classpath.
Full report at:
/tmp/clojure-90572729667538797.edn
$
I tried exporting CLASSPATH env variable to ".", or pass it somehow with command line parameters, but none of these helped.@thoneyvazul you need a deps.edn
file adding the current directory to the classpass (you also need to add & args
to your -main
function args)
I'd be interesting on knowing if there's a way to modify classpath without a deps.edn
file
How can I sum up all pair freq (bi-grams) to a map using reduce?
(def pairs '(("ab" "bd") ("ab" "bc") ("ab" "bk")))
(def freq '(1 2 3))
(defn f [p f])
=> {"ab" 6, "bd" 1, "bc" 2, "bk" 3}
{:low 5 :lowest 2}
pairs will be (('lo', 'ow'...) ('lo', 'st'))....etc
freq (5, 2)
applying f will yield:
=> {"lo" 7, "ow" 7 "we" 2,...etc}
Ah, I thought def freq
was a typo.
You probably just need to write your own function.
But there's a much simpler way without doing reduce
.
The function frequencies
takes a sequence and returns a map.
You just need to flatten
your data structure first.
but I want the frequencies to be determined by the freq itself
I'm sorry, now I'm confused again.
'ab' is 3x with frequencies
but in my situation it's 6
Why do you want it to produce 6
?
It only appears 3 times.
freq is a constant, it determines each pair with it frequency
i'm not trying to get the number of it appereances
Oh, THAT's what that's for.
think of that I have some frequency already calculated, and I want to generate pairs from it with each -sums freq
for example
Well... I'd write a function that multiplied each sequence by the number in the frequency that matched the sequence.
You could use reduce
for that.
{:low 5 :lowest 2}
=> {"lo" 7, "ow" 7 "we" 2,...etc}
I get a frequencies map and I want to create it pairs-frequency (from it keys)
yep that's generated my def pairs
Focus on each key value pair individually. Later, merge two maps using merge-with and +.
no way to do this with reduce in one time? accumulating the result-map?
@aviv you can use repeat
to repeat each pair the corresponding number of times, mapcat
that together into one long seq of strings, and then apply frequencies
on that. Not the prettiest but looks like this:
(frequencies (mapcat (comp #(apply concat %) repeat) freq pairs))
You can use seq
on a map to get the entries, like this, (seq {:low 5 :lowest 2}) => ([:lowย 5]ย [:lowestย 2])
.
One inefficiency in my suggestion above is, if there's a huge number in freq
, then we'll end up creating a massive seq instead of simply multiplying the counts. This approach doesn't have that limitation:
(defn mapvals
"Maps f on values of map m"
[f m]
(into (empty m)
(map (fn [[k v]]
[k (f v)]))
m))
(->> (map frequencies pairs)
(map (fn [n fs]
(mapvals #(* n %) fs)) freq)
(apply merge-with +))
We get the frequencies of each pair, then multiply those values with the corresponding frequencies, then merge all those maps together with +
to add 'em up.@UJRDALZA5 how would that help to count the pairs (bi-grams), i can generate pairs then use map f' pairs freq
then merge result as you have noted,
I tried this,
(defn pair-freqs
[m]
(reduce (partial merge-with +)
(for [[k v] m]
(zipmap (partition 2 1 (name k)) (repeat v)))))
(pair-freqs {:low 5
:lowest 2})
;; => {(\l \o) 7, (\o \w) 7, (\w \e) 2, (\e \s) 2, (\s \t) 2}
Here, for
internally calls seq
on the map and I am destructuring that into key-value pair.
We don't usually need to call seq
on a map but many functions that expect a sequence can take a map and what they'll get is a sequence of entries. That is very useful.
Interesting, i'll check it out, thanks!
vals
will return a sequence of all the values in your map, with no keys.
Just use reduce
on that.
I do not have a map
each pair is corresponding to it freq, so 'ab':1 then 'ab':2 then 'ab':3, total freq of 6
That's what freq
returns.
A map of all the frequencies.
Unless I'm completely confused.
let's thread on this
is there a way in spec to add additional description?? I mean if i create (s/def application-id int?) i could add a written description and explain what is the application-id. Then the same โdescriptionโ would also be shown in swagger
So we are aware of the desire :)
with spec-tools, you can say:
(require '[spec-tools.core :as st])
(require '[spec-tools.swagger :as swagger])
(swagger/transform
(st/spec
{:spec integer?
:name "integer"
:description "it's an int"
:swagger/default 42}))
;{:type "integer"
; :title "integer"
; :description "it's an int"
; :default 42}
okay, maybe I need to go and vote it also (if possible).. And thanks, I will check spec-tools out :thumbsup:
curious - are there any production-teams using Property Based Testing? if so - with/without TDD? mixing? what are your thoughts? new to it and thinking on adding to our pipeline..
@aviv what am Property Based Test?
We have mostly a traditional test suite with a few generative/property based tests. We don't have a separate generative test suite that takes a long time to run, which I have seen mentioned as a best practice. Our generative tests if they potentially take forever to run default to a small iteration count, but can be increased using a environment variable if you want a more complete test run. I am definitely not doing TDD
Not doing TDD as this have replaced / over-taken your testing pipeline?
so your test pipeline includes only property-based-testing?
I currently use TDD and looking for alternatives
by TDD I mean having test-by-example, and lots of them
*T*est *D*riven *D*evelopement is the practice of writing tests first and using those tests to guide creation of the implementation
as I said, I don't practice TDD, but the majority of our tests are a traditional test suite (example based tests) with a few generative/property tests sprinkled around
I use TDD for some things -- such as where we have a clearly defined spec with success and failure behavior well-documented up front, such as new REST API endpoints. I'll write failing tests for that around the specific types of failure and a simple success case, then write code to make them pass, then more tests and more code, and refactor while "green".
Where things are less well-speced, I'm more likely to do RDD to explore the shape of the problem/solution.
I know hiredman, I skipped the introduction because the relevancy to PBTesting is the test-by-example vs test-by-property
If I have something that is based on ranges of data with boundary conditions, I'll use PBT (earlier this week, I wrote PBT for some conversion/formatting functionality).
(disclosure: hiredman and I work together -- so our responses, taken together, reflect the wide range of our approach to development/testing)
heh ๐ awesome
using generators
from test.check
I'm receiving exception with error
Couldn't satisfy such-that predicate after 100 tries.
when I try to generate none-empty vectors
with 'tokens' -> strings which are lowercased + not empty
(gen/such-that (complement empty?)
(gen/vector (gen/such-that lowercase? gen/string-alphanumeric 100)))
I understand that the generators are unable to create my desired input - but this seems like a very 'decent' request, is there any alternative generating such? or anyway to stop from exception being thrown?such-that can only filter (remove stuff that doesn't match) from the given generator (string-alphanumeric in this case)
it is much more efficient to generate exactly what you want, but that is usually going to require writing a custom generator
you could also transform the output of the generator instead of filtering, e.g. instead of throwing out all the generated strings that are not all lowercase, you can take whatever generated string and make it lower case
On the same topic, can you spec a key which would be a value? I used fn?
as predicate, but who can I fake the return values, or define the return values?
I guess I could use a generator of a set.
{:f (fn [x] (* 2 x))}
How would you spec :f?
I still didn't understand "key which would be a value" -- did you mean "key whose value is a function?"
@ghadi Yes, this is what I desired to mean
If I was just doing a API/ server in Clojure , are people still using ring/compojure? Any new templates people would recommend?
I believe I've used https://github.com/weavejester/compojure-template in the past
There was a survey by Eric Normand (?) where he points to ring/Pedestal/yada for production services.
https://github.com/metosin/compojure-api is a great template for creating an API in Clojure. It also includes swagger (open api) to automatically generate live documentation and test web interface for the API.
At work, our (REST-ish) API Server is Ring/Compojure (and Component and a bunch of other stuff). @thurmondmb
Thanks @seancorfield wasn't sure if there was anything new in the past year or so
If we were starting over, maybe we'd look at other libraries more focused on APIs. Maybe compojure-api
, or reitit
, or something. But Ring/Compojure is fine as basis for most stuff. And I almost never use a template when starting a project (even tho' I created boot-new
and clj-new
for that purpose!).
(well, I might use clj-new
to create a very basic app
template, but that's it)
FWIW, I like to start from the basics because most templates that do more than very simple stuff are far too opinionated for my tastes ๐
If I went the ring/ compojure route I could then add in Clojure spec or schema for validation?
And a swagger docs dependency if I needed it later on?
Sure. It's all just libraries.
Even when I start from just a basic app
template, I usually end up with dozens of dependencies by the time I'm finished. I just find it easier to build things up as I go.
Cool thanks
Also, clojure.spec
is pulled in automatically if you're using Clojure 1.9 or 1.10 (1.10.1 is the current stable release, 1.10.2 is in alpha right now).
(I just checked our API project at work and it looks like it has 16 top-level dependencies that bring in around 150 total libraries via transitive dependencies -- most of those top-level deps are actually other subprojects at work, so second-level deps would be a more realistic measure which is around 90 libraries)
Thanks !!
(our "core" business project, reused by everything else, has almost 60 top-level dependencies)
I'm going to try to build it from the ground up. When I was working in Clojure full time , my boss created our server that way was well. This was also before a lot of templates were available