This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-04-09
Channels
- # announcements (3)
- # babashka (1)
- # beginners (66)
- # clj-kondo (2)
- # cljdoc (46)
- # cljs-dev (7)
- # clojure (16)
- # clojure-australia (2)
- # clojure-china (1)
- # clojure-europe (3)
- # clojure-hk (1)
- # clojure-japan (1)
- # clojure-korea (1)
- # clojure-my (1)
- # clojure-sg (1)
- # clojure-taiwan (1)
- # clojurescript (4)
- # community-development (53)
- # conjure (6)
- # css (7)
- # cursive (6)
- # datascript (1)
- # datomic (5)
- # exercism (5)
- # graalvm (12)
- # helix (8)
- # jobs-rus (1)
- # kaocha (1)
- # lsp (19)
- # nrepl (1)
- # overtone (2)
- # pedestal (1)
- # polylith (2)
- # portal (2)
- # react (25)
- # reagent (1)
- # shadow-cljs (7)
- # spacemacs (8)
- # vim (9)
If I wanted to craft a very lightweight GraphQL api for a toy project that doesn’t need to talk to a DB at all, just something in memory, should I use lacinia-pedestal, or is there another solution?
I know you're excluding databases here but just in case you haven't seen it: hasura is amazing and easy to set up and use
https://github.com/juxt/grab is described as a minimal graphql library. No docs yet, but examples of use in the project unit tests I've also used Hasura (local docker image rather than service) which was just pointed to tables in postgres database and generated a Graphql API service. Hasura has an okay console for configuration, which can also be done in Yaml.
https://www.apollographql.com/docs/studio/ is a very nice Graphql client (free online service, with commercial extras)
For example, clojure.math
is wrapper over Java's Math
, so you don't have to know Java or search in Oracle docs to do something. And these functions are better documented, you can require them under shorter name and are easier to use (e.g. mapping without using anonymous fn):
(require '[clojure.math :as m])
=> nil
(map m/sin [90 0 180])
=> (0.8939966636005579 0.0 -0.8011526357338304)
(map #(Math/sin %) [90 0 180])
=> (0.8939966636005579 0.0 -0.8011526357338304)
(doc m/sin)
-------------------------
clojure.math/sin
([a])
Returns the sine of an angle.
If a is ##NaN, ##-Inf, ##Inf => ##NaN
If a is zero => zero with the same sign as a
See:
=> nil
(doc Math/sin)
=> nil
@U01RL1YV4P7 Thank you for your response, In web application, we make use wrap-params
and wrap-multiparrams
similar kind of wrappers, what does it do
Oh, that's something different. I'd say that wrap-
is conventional prefix for middleware name.
And middleware is higher-order function, which takes handler and returns a new handler with some added behaviour. See this: https://luminusweb.com/docs/middleware.html
A wrapper can be either 1) a Clojure project that explicitly provides functions around a library, usually in another language like Java or python (jython) 2) a middleware function that is called to process data coming into / out of a handler function (e.g. ring middleware) I guess the main different is the scope of thing being wrapped
In a more general and all-encompassing sense, perhaps one could say that a wrapper is an alternative interface that makes the underlying interface(s) (the “thing(s)” being wrapped) easier to use in a particular context or situation.
I expect it returns a new vector containing the individual characters of the string “clojure”…
play=> (doc vec)
-------------------------
clojure.core/vec
([coll])
Creates a new vector containing the contents of coll. Java arrays
will be aliased and should not be modified.
vec
creates a vector when given a collection. Strings are considered collections of characters. So
play=> (vec "clojure")
[\c \l \o \j \u \r \e]
play=> (type \c)
java.lang.Character
which is a vector of the characters c, l, o, .... The repl prints characters as \c

It is highly recommended to try such things out yourself in a local Clojure REPL to find out, by the way. A great way to get quick answers to such questions. Even if you do that, it is still certainly reasonable to ask questions like "WHY does it behave this way?"

so \c
is type of character and we can use it like any other symbol :a
"a"
. I'm trying to find the frequency of character in a string. So I'm doing following
(frequencies (vec "clojure-rocks"))
and find any frequency this way
(get (frequencies (vec "clojure-rocks")) \c)
Is that right?play=> (frequencies "clojure")
{\c 1, \l 1, \o 1, \j 1, \u 1, \r 1, \e 1}
you don't need to vec
the string since it is already a collection. And then you can access the resulting map however you like
but the advice above was correct. play in the repl. cause errors. evaluate sub forms, etc
Yes, I'm doodling in REPL. Still didn't comfortable completely. This language surprising me each day.
> you don't need to vec the string since it is already a collection
it isn't a collection, but frequencies
(like most clojure collection functions) implicitly calls seq
, and seq
works on strings
I think sequable is the term (see the seqable?
function)
user=> (seqable? "foo")
true
is there a good reason why (class (hash-map))
=> clojure.lang.PersistentArrayMap
? seems like if you're calling hash-map
with no args it should be an alias for clojure.lang.PersistentHashMap/EMPTY
The optimization around PersistentArrayMap and PHM is purely implementation details.
But reading the source, hash-map
doesn't waste time counting args. It just makes a transient based on the PHM, stuffs everything in it and then gets a persistent version of it.
The rule of thumb I've heard is that if you care which implementation you have between PAM and PHM you are doing it wrong.
I do not claim this is a good reason, but I suspect the true reason is that for most users of Clojure maps, they have no reason to care whether the class implementing it is a persistentArrayMap or a persistentHashMap
yeah, not saying that there's a good reason to care in practice. but since the hash-map
function is provided to explicitly create a hash map, it seems surprising that it doesn't actually do this for the 0-args case
The function map? returns true for both, for example, and almost all functions on maps return equal results for the same operations on both
i'm not following the surprise. it creates a hashmap and does so for the 0-args case
> Returns a new hash map with supplied mappings. seems like that promise was delivered
Well, my assumption is that a PAM is not a "hash map", even when empty. It's a map, but not a hash map.
Part of my surprise is due to the first example on the https://clojuredocs.org/clojure.core/hash-map for this function making a distinction between the {}
syntax for creating an "array map" and (hash-map)
for creating a "hash map". But in practice they both create array maps.
Unlikely that this would ever be an issue in practice, sure. Just a bit surprising to me, since hash-map
returns a PHM in every other context (even when using map literal syntax would produce a PAM). So I was curious if there was an explicit reason for this. Perhaps not.
Note that http://Clojuredocs.org is community written content, except for the official doc strings that are simply copied from official Clojure releases. The Clojure core team does not vet, approve, or in any way endorse the community written parts of it, unless maybe somehow they make special cases where they explicitly do (but I am not aware of any cases that they go out of their way to do so)
Understood, just mentioning it as a cause of my initial surprise about this behavior. Clearly someone else had similar assumptions here.
it's something about PersistentArrayMap being used for small maps and over a certain number of keys it uses PHM (iirc)
as an optimization
Reading the source of j.u.HashMap
. It also has some optimizations. https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/HashMap.java#l211 When making the buckets, if lots of things go in the bucket it will change from an array of nodes to a tree of nodes: https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/HashMap.java#l642
This type of optimization is common in these things. The docs of this class and https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/LinkedHashMap.java point out that small hash maps are extremely common. Clojure takes advantage of this and the equality semantics of Clojure to provide an even better optimization: the array map. Because of Clojure's equality semantics, we don't even have to explicitly hash things, we can just keep a 16 wide array and traverse through it because this is faster to walk that and check a notion of equality than to hash, consider collisions, etc. But it is still a "hash map", just a tuned and optimized one
@U11BV7MTK Well, I would say that a PersistentArrayMap is still a Clojure map, but it is clearly not a PersistentHashMap, which is sometimes what a Clojurist means when they say hash map.
As mentioned above, for almost all use cases, PersistentHashMap and PersistentArrayMap are indistinguishable from their behavior.
Yeah, that's the crux of my initial question. Since there are distinct hash-map
and array-map
functions which specifically return instances of PersistentHashMap
and PersistentArrayMap
for all non-empty cases, it seemed odd that this wouldn't be true for the empty case as well.
If the answer is just "the implementation shouldn't matter to the end user" then why expose distinct array-map
and hash-map
functions in the first place?
What I've landed on is that array maps have additional semantics over hash maps: they preserve the input order of elements. So this warrants having array-map
as a distinct function for constructing them, for maps > 10 elements.
But you don't get any additional semantics by using a hash map where you'd otherwise have an array map. So there's no downside to the end user for having (hash-map)
return an empty array map, despite the function name.
Anyway, none of this has a motivating problem, just curiosity, so not worth digging into too deeply.
I'm learning a little core.async and I made a small wrapper around the hato callback API's get
to return a core.async
channel. Does this seem problematic at all? The simplest version of this would be just to create a channel, and have the success/failure callbacks both put!
asynchronously to the same channel and then return that channel. Does adding a go
block here for some instrumentation make this behave in any kind of unexpected way? Does this look fine?
I have implemented a function that takes a sequence of maps and prints it as tab-separated values:
(defn print-tsv
([ks rows]
(when (seq rows)
(println)
(println (str/join "\t" ks))
(doseq [row rows]
(println (str/join "\t" row)))))
([rows] (print-tsv (keys (first rows)) (map vals rows))))
Input
(print-tsv '({:log "some text", :id 123} {:log "some other text" :id 124}))
Output
:log :id
some text 123
some other text 124
How could I rewrite my function to return the output as a string rather than print it?(defn print-tsv
([ks rows] (->> (map #(str/join "\t" %) rows)
(str/join "\n")
(str (str/join "\t" ks) "\n")))
([rows] (print-tsv (keys (first rows))
(map vals rows))))
(print-tsv '({:log "some text", :id 123} {:log "some other text" :id 124}))
=> ":log\t:id\nsome text\t123\nsome other text\t124"
By the way, you can use print-table: (with-out-str (clojure.pprint/print-table [{:log "some text", :id 123} {:log "some other text" :id 124}]))
Thanks to both of you. Yeah, I'm aware of clojure.pprint/print-table
, but for my use-case I want a tsv rather than a pretty table.
one way of doing it:
(defn as-tsv
([ks rows]
(when (seq rows)
(cons (str/join "\t" ks)
(for [row rows]
(str/join "\t" (map row ks))))))
([rows]
(as-tsv (keys (first rows)) rows)))
(run! println (as-tsv '({:log "some text", :id 123}
{:log "some other text" :id 124})))
I prefer making a sequence of lines to making one whole string so that I don't force all the data into memory at once as a big string. Then it's simple to print them out with (run! println ...)
.
Also, a potential issue with your first impl is the (map vals rows)
in the single arity call. That assumes that the values are all in the same order for all maps, which is only true if they have 8 or fewer keys. After that they're not in order.I am reading a tsv using the below code
(-> "/Users/konrad/tmp/input.tsv"
io/file
io/reader
(csv/read-csv :separator \tab)
(csv-data->maps)
first)
and get the output
{::a "1",
::b "2",
::d "3"}
If I evaluate
(-> "/Users/konrad/tmp/input.tsv"
io/file
io/reader
(csv/read-csv :separator \tab)
(csv-data->maps)
first
::a)
the output becomes nil
.
However, if I evaluate
(-> {::a "1",
::b "2",
::d "3"}
::a)
I get
"1"
Why do I get the output nil
when I use ::a
in the second snippet?the answer is most likely in understanding what ::a
means. keywords can have a namespace. using an autoresolved keyword like ::a
means use the current namespace. Are you running this from a repl or are you running it from the command line?
The source of csv-data->maps
is
(defn csv-data->maps [csv-data]
(map zipmap
(->> (first csv-data)
(map keyword)
repeat)
(rest csv-data)))
I am running the code in a cider repl in emacsi suspect you are making funny keys then. drop the map keyword
bit and see what the output is for the first row of the csv
If I comment out (map keyword)
from csv-data->maps
and run
(->>
(-> "/Users/konrad/tmp/input.tsv"
io/file
io/reader
(csv/read-csv :separator \tab)
(csv-data->maps)
(first)
(get ":a"))
I get the expected output
"1"
the function keyword
will take a string and return a keyword. But it won't validate it. you want those columns to be named "a"
not ":a"
play=> (= :a (keyword "a"))
true
play=> (= ::a (keyword ":a"))
false
play=> ::a
:play/a
play=>
Indeed, thanks.