This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-04-17
Channels
- # announcements (4)
- # aws (17)
- # beginners (108)
- # calva (2)
- # clojure (164)
- # clojure-austin (1)
- # clojure-europe (3)
- # clojure-italy (1)
- # clojure-nl (17)
- # clojure-uk (98)
- # clojurescript (31)
- # code-reviews (1)
- # cursive (23)
- # data-science (1)
- # dirac (6)
- # emacs (21)
- # figwheel-main (1)
- # fulcro (53)
- # graphql (2)
- # hoplon (1)
- # lein-figwheel (1)
- # leiningen (2)
- # lumo (21)
- # off-topic (118)
- # onyx (4)
- # pathom (59)
- # pedestal (2)
- # planck (3)
- # reagent (47)
- # reitit (2)
- # shadow-cljs (258)
- # spacemacs (3)
- # sql (10)
- # tools-deps (37)
I can only think of one way to get the cartesian product of two infinite seqs, but it's not very fast.
You can employ the same trick that is used to show countable cardinality of products of uncountable sets.
https://en.wikipedia.org/wiki/Pairing_function#Cantor_pairing_function
The image explains the idea:
https://en.wikipedia.org/wiki/Pairing_function#/media/File:Diagonal_argument.svg
It's basically two nested loops to determine which nth
to take from each sequence.
I'm trying to create an API using compojure and the middleware functions are of the format
:middleware [mw/a mw/b mw/c]
And I was wondering if there is a way to define something like
(def common-mw [mw/a mw/b mw/c])
so I can do :middleware [mw/common-mw]
? (I've tried this and it doesn't seem to work)common-mw returns a vec, so your invocation looks like :middlware [[mw/a mw/b mw/c]]
. Have you tried :middleware mw/common-mw
?
I have, but let me try it again
(I was getting an error but can't remember what it was)
Don't know how to create ISeq from: clojure.lang.Symbol
do you have a snippet of your method invocation? Are you using metosin/compojure-api ?
yes, I'm using compojure-api, sorry, new to all of this so I didn't realize the difference between the two.
(def token-backend
(jws {:secret (env :secret) :options {:alg :hs256}}))
(defn authenticated
[handler]
(fn [request]
(if (authenticated? request)
(handler request)
(unauthorized {:error "Not authorized"}))))
(defn token-auth
[handler]
(wrap-authentication handler token-backend))
(defroutes profile-routes
(POST "/" []
:header-params [authorization :- s/Str]
:responses {created ProfileRequestSchema}
:body [create-profile-req ProfileRequestSchema]
:middleware [token-auth authenticated]
(create-profile-handler create-profile-req)))
It's a bit of a complicated error but the source for the 'POST' macro is here: https://github.com/metosin/compojure-api/blob/00d6e3a25c442dcf060f5f6d5aa71e830db142bf/src/compojure/api/core.clj#L66
Because it's a macro which then calls a function, the function is called at macro time which means that the args aren't evaluated yet (or something like that)
Basically you have to have it as a literal list rather than defining a var
(Unless you cheat and define your own macro that returns the middleware, but that sounds like a very poor solution)
(again new) to treat it as a literal list would I do
(def auth-mw '(token-auth authenticated))
so I get this error:
clojure.lang.PersistentList cannot be cast to clojure.lang.IFn
and if I don't do the [] I get Don't know how to create ISeq from: clojure.lang.Symbol
Here's a simple example of the problem that you're having:
(defn my-fn
[arg]
(println (first arg)))
(defmacro my-macro
[arg]
(my-fn arg))
(my-macro [1 2 3 4])
;; => 1
(def my-var [1 2 3 4])
(my-macro my-var)
;; => IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Symbol clojure.lang.RT.seqFrom (RT.java:542)
If you swap out the my-macro
definition with the following it might make more sense for you:
(defmacro my-macro
[arg]
(println "my-macro arg:" arg)
(my-fn arg))
The first example prints my-macro arg: [1 2 3 4]
The second example prints my-macro arg: my-var
That makes sense basically it's not interpreting my def
as a list but rather just passing the argument through
so there isn't a way to do what I want to without writing my own macro?
.... or can I use eval
?
I guess that would be the same issue
You're right you'd have the same issue there
There might be some kind of inline
macro you could use
Or you could write one
That way it would be a little cleaner
Maybe the takeaway from this is that writing macros is hard, it certainly is for me 🙂
lol, yeah, that's what I've been trying to avoid 😆
not something I think I'm ready to tackle, thank you both for all of your help!
I took another look at why the library was behaving this way and I think I tracked it down to a couple evaluations of (if (seq middleware) ... )
in meta/restructure
https://github.com/metosin/compojure-api/blob/00d6e3a25c442dcf060f5f6d5aa71e830db142bf/src/compojure/api/meta.clj#L678
I'm interested to know the best way to modify the macro to make it work how we hope. I suspect it's a combination of checking the type of middleware
at compile time instead of just assuming it's Seqable
for starters, "/"
needs to be #"/"
you could use peek instead of last for a minor perf improvement, I don't know if that makes the code any clearer
@somedude314 you can also use threading, it may or may not make this code more clear, but with more nested calls it tends to be helpful
user=> (-> "a/b/cd" (clojure.string/split #"/") (peek))
"cd"
Yeah, I am familiar with threading. It's just I am still hesitant writing Clojure code because I often find there's a shorter and cleaner way to do what I came up with 😄
there are various regex pattern tricks for things like this - generally googling/so'ing for Java solutions will find compatible answers
and https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html for reference
like you can probably use some kind of negative lookahead with capture to match only the last, although I can't say I have the details at hand
this site is excellent quality for general regular expression features and tricks, it breaks things down per implementation https://www.regular-expressions.info/
if you do use something like this, leave a comment so the next person that wanders along has a clue what you did :)
You certainly can use some fancy regex, but whether its worth is is a different story. Code golfing got me to (re-find #"(?<=/)(?!.*/.*).*$" "a/b/cd")
, which matches a /
but doesn’t consume it followed by anything that is not a slash and a line terminator. Please don’t do that, the next one reading that code will … have a funny look in his/her face
So thats (?<=/)
, match a slash but don’t consume it. (?!.*/.*)
lookahead whether there is no following slash and .*$
match anything else followed by an end of line
again; you probably don’t want to
… I just got carried away by “can this be regex’ed”, which ends up being “yes” most of the time.
(I mainly wanted to share to show the incredible power of regex ^^!)
That produces two matches, one for the entire string and one for your capture group
So it would work if you do a non-consuming match like this: (re-find #"(?<=^.*/)[^/]*$" "a/b/cd")
Yes! please do
I don't think you'd ever need this version, but it avoids allocating strings and collections, and is more readable than the pure regex version
(defn lastmatch
[string re]
(let [m (re-matcher re string)]
(loop [start nil
end nil]
(cond (.find m) (recur (.start m) (.end m))
start (subs string start end)
:else nil))))
but that asks for the inversion of the splitting regex (`#"[^/]+"`) rather than the splitting regex itself
there's a loose idiom of suffixing ! to name things that do side effects, and a db call is a side effect; it's inconsistently followed
I wouldn't use an ns to indicate something touches the db - most namespaces will have a mixture of various levels of code plus helper code and useful constants.
I've never even seen clojure code try to segregate things that way
@noisesmith just found this https://gist.github.com/noisesmith/ebe8b3f185e34a7de04b1189b21ba59b - do you still use it? how did it work out?
checking if I modified it since...
that's the version I still use, it's pretty good (imperfect since it's regex based of course)
first hit on google was https://gist.github.com/vladh/1e1e7bc5eb274235e0b9
iirc mine was extended from that one
I have a hunch that vladh gist misses a bunch of valid (though semi-rarely-used) identifiers, and if I'm reading it correctly it also matches invalid identifiers like 1foo
wow, they both lack deftype :/
and defrecord!
so yeah, this could clearly use improving
another thing the vladh one misses that mine doesn't is metadata eg (defn ^:foo bar [] ..)
- mine recognizes that as defining bar, the other doesn't
cool, since mine is already a community effort I should make a github repo for it
yep, I'll complement it with other emacs stuff, do you rebuild the index on every save?
I typically rebuild before doing tag queries (I'll often do a few different ones in a row), the latency of rebuilding the full tags is indistinguishable from the latency on normal editor commands on any computer I use for development. It would be smart to hook tag building into save though.
@lockdown- hard mode: define a tag regex that matches a protocol method definition but not its implementation(?) - or maybe it's worth it to catch both
that might in fact be impossible given line oriented regex based definitions
OOOOOH - the "pattern" is actually an
I misred, it only uses ex commands to find the tag on lookup, not to parse code for tagsex
command, so with some work you could probably find and match protocol methods inside a protocol...
I still haven't studied clojure's protocol but sounds worthy 😉, you don't use some grep tool? ag, ripgrep, grep, git grep, etc...
I’ve been using grep inside the repl to search for methods
how is the swiper emac plugin? Is it a code auto complete plugin?
no, with something like ag, it lets you search for names project wide with a nice overview
ahh, similar to grep?
I typically use the default tag lookup in neovim, or the built in :grep ...
then I use :cope
to browse and follow the list of matches
@lockdown- a more reliable method to find implementations uses the source metadata that the compiler collects and puts on vars, this requires integrating a repl client into the editor (eg. vim/fireplace intellij/cursive emacs/cider)
between these two calls in a vanilla repl, you have all the info needed to open a file to a specific line:
(cmd)user=> (pprint (meta #'clojure.core/reduce))
{:arglists ([f coll] [f val coll]),
:doc
"f should be a function of 2 arguments. If val is not supplied,\n returns the result of applying f to the first 2 items in coll, then\n applying f to that result and the 3rd item, etc. If coll contains no\n items, f must accept no arguments as well, and reduce returns the\n result of calling f with no arguments. If coll has only 1 item, it\n is returned and f is not called. If val is supplied, returns the\n result of applying f to val and the first item in coll, then\n applying f to that result and the 2nd item, etc. If coll contains no\n items, returns val and f is not called.",
:added "1.0",
:line 6810,
:column 1,
:file "clojure/core.clj",
:name reduce,
:ns #object[clojure.lang.Namespace 0x13f95696 "clojure.core"]}
nil
(cmd)user=> ( "clojure/core.clj")
#object[java.net.URL 0x66746f57 "jar:file:/Users/justin.smith/.m2/repository/org/clojure/clojure/1.10.0/clojure-1.10.0.jar!/clojure/core.clj"]
that's a resource (even works inside a jar), plus a line and column
dev=> (clojure.pprint/pprint (meta #'connection)) {:arglists ([]), :line 1, :column 1, :file "NO_SOURCE_PATH", :name connection, :ns #object[clojure.lang.Namespace 0x4c39ad4a "dev"]} nil dev=> (http://clojure.java.io/resource "dev") nil dev=>
this is a result of loading via an nrepl editor integration rather than require
iirc
NO_SOURCE_PATH generally means "this was defined directly in a repl and the compiler didn't know of any file it might have come from"
wow… I want to share my favorite vim command, ever… for alphabetize sorting… https://thoughtbot.com/blog/sort-lines-alphabetically-in-vim
I just alphabetized my css/sass imports in 2 commands