This may be the dumbest question ever but, does having both Leiningen and Clojure CLI Tools installed cause any conflicts?
perfectly sensible question.
nope
lots of projects have a project.clj
and a deps.edn
@luishendrix92 deps.edn
for Clojure CLI tools and project.clj
for Leinignen do not have relationship with each other.
I've added a deps.edn
configuration to leiningen projects before so I could use Clojure CLI tools instead. It is usually just adding the :dependencies
from project.clj
to :deps
in deps.edn
, along with any aliases for tools or paths.
One caveat, if the code relies on Leiningen plugins, like lein-ring
, which injects code into the codebase to be able to run a server, then you would need to add that code to make Clojure Cli tools work. This might cause a conflict with Leiningnen plugins.
:validate = ( clojure.core/fn [ % ] ( clojure.core/contains? % :condition ) )
I have the above in a hash map, I want to access parts of the value but I get Don't know how to create ISeq from: clojure.lang.Symbol how can i run (last (last (:validate data))) on the above ?I feel like it should be easy but I am missing something
(last (last '( clojure.core/fn [ % ] ( clojure.core/contains? % :condition ) )))
I figured out that does what I need, it just does not work with the version inside the hash map
lots of quoted stuff going on and a random =
. Can you show a bit more concretely what you have? it sounds like you have {:validate (fn [s] (contains? s :condition))}
is that true?
yeah that's correct, the equals is from cider inspect π
ok. given this map, what would you like to do?
I am basically after :condition which last last would give me
I understand its because the value is basically a fn just not sure how to make it a list that i can manipulate
in my example i've put the key :validate
is mapped to a function and at that point its opaque. You can't get into it
you cannot
oh so regex out the value is my only hope at that point
if you just have a funtion, no, you cannot regex it either
please correct me if you aren't dealing with a function though
okay thanks for clarifying well i can str the function
(str +) -> "clojure.core$_PLUS_@3478c93b"
(str (:validate data)) for example
it seems to give me the string version of it
it's not though, it's a list
functions are compiled jvm code. they don't have string representations beyond a bit of munged name and an address
you do not have a function then. can you show some example code of how you're making this map?
@dpsutton it's a quoted list
that would be a function if it were evaluated
that's the only way the inspector would show that
clojure.repl/demunge may be useful if demunging class names
it could be a quoted list, but should last not work on a quoted list ?
@oliver.marks what's your goal here? what do you want function shaped lists for?
is this parsing spec output?
yes I am parsing spec, I do know about expound but it's not flexible enough
at my last job we had some clever core.match usage to pattern match on those
so if its a quoted list should I be able to manipulate it / treat it as data
yes
(take 3 (iterate (fn [x] (if (seqable? x) (last x) x)) '( clojure.core/fn [ % ] ( clojure.core/contains? % :condition ) )))
((clojure.core/fn [%] (clojure.core/contains? % :condition))
(clojure.core/contains? % :condition)
:condition)
so that works like in the example where its quote '() but when it comes from spec it errors on clojure.lang.Symbol
which is what i don't 100% do i need to run it through another fn first
the error message above is saying it cannot create an ISeq from a Symbol. It sounds like you're calling last on a symbol which obviously can't work
there are many function forms that you can't call (comp last last)
on without that error
I guess its back to using str and regex then for now π
you could use the spec for fn
to s/conform the list representing a function
it will "parse" it for you
user=> (s/conform (:args (s/get-spec `fn)) (rest '(fn [x] (if (seqable? x) (last x) x))))
{:fn-tail [:arity-1 {:params {:params [[:local-symbol x]]}, :body [:body [(if (seqable? x) (last x) x)]]}]}
nice I will give that a try and see what happens π
clojure is doing exactly that to verify the spec for all registered spec macros
it a shame spec errors using (s/keys) does not store the key that's missing in an easier to access format
you can also use spec specs to s/conform a spec :)
https://clojure.atlassian.net/browse/CLJ-2112 has some work on spec specs, although really the map data forms in spec 2 are probably more useful as a future direction
question about comparing symbols. I have two symbols. I have required [clojure.spec.alpha :as s]
into my namespace. But when I try to compare s/and
with clojure.spec.alpha/and
using =
it returns false. Are these really two different symbols? I thought they were the same symbol? I suspect I'm asking the wrong question, but how can I compare s/and
to clojure.spec.alpha/and
to get true
?
they are literally different symbols. you could resolve
both and see if they refer to the same var
whether s = clojure.spec.alpha depends on your current *ns*
so it's contextual
if I alias s to clojure.string then ...
the namespace object is the one that holds alias mappings and ns is what tells you which namespace object to use for resolution right now
@jimka.issy if this helps, there's a hash-map that the namespace owns, that maps from symbol to var, and the "namespace" part of a namespaced symbol is used to decide which map to look in when resolving
https://raw.githubusercontent.com/cognitect/clojure-lab/master/images/namespaces-total.svg
^^ big picture
This seems to work. I've never used condp
before, and I was surprised that I need to quote the clause "tests" ('s/and 's/or), which is not the case with case.
(condp (fn [x y] (= (resolve x) (resolve y))) 'clojure.spec.alpha/and
's/and 1
's/or 2)
case is super weird
case works with compile-time constants. b/c they're constants, they don't need to be evaluated
a lot of weirdness in case is due to the special circumstances of the switch bytecode it's trying to leverage
right - there's so many special-case situations for case that don't apply to the rest of clojure
like how it treats lists, and symbols for classes off the top of my head
well, if anyone ever bothered to read the docstring...
I'm not saying the special cases are secret, just that it has a lot of them
case
is normal. Every lisp treats it pretty much the same way. clojure, emacs lisp, scheme, common lisp. No surprises there. That condp
looks like case, but acts differently was a surprise. It's clear why the main expression needs to be evaluated, but not yet clear to me why the clauses need to be evaluated. Not exactly clear from the docstring either. At least with a casual reading.
Hi all. Newbie here π I have a spec generator question. I was trying (-> ::expression s/gen g/generate)
and I ran into the sample limit issue. ::expression
is a recursive spec of simple arithmetic-like calculator with def
and if
like additions. I have been digging around and it seems my naive use of s/or
just makes it worst. I was wondering if anyone has any pointer on how to understand/debug why the generator struggles. (I found s/*recursion-limit*
suggestions online, but did not help much). Thanks for your time in advance!
@xllora generators are quite naiive, and if your spec has an arbitrary function to test, it will create random inputs until one passes
usually I'd use a custom generator with the help of things like gen/fmap to create things the spec actually accepts
@noisesmith does that mean that the default generator would be generating values for all the leave predicates and then just check if valid?
(fmap helps especially if there's two parts of the input data that have to "agree" in some way)
@xllora if I understand what your asking yes, it's not clever
it looks at the types you accept, and creates things that might fit, and uses yours spec to filter
it's not hard to make a spec such that no appropriate example would be created after 1000 tries
especially in your case where it sounds like you are parsing an expression language
I see. Then s/or
is not actually selecting a branch and expanding it, but both hence making impossible to satisfy? Yes
(s/def ::data-primitives
(s/or :number number?
:symbol symbol?
:char char?
:string string?
:bool boolean?))
this two-column output displays very badly in the slack client
Sorry, jumped the gun accidentally hitting return π
Then there is the usual recursive definition on expression around +, -, ...
around it
I notice from the error message though, it's not ::data-primitives that fails to generate, it's ::expression
yeah, that's your problem, not s/or
the error, which you deleted because it was formatted weirdly, was about generating ::expression
Execution error (ExceptionInfo) at clojure.test.check.generators/fn (generators.cljc:435).
Couldn't satisfy such-that predicate after 100 tries.
If I understood your point, your suggested is to check fmap
to generate a custom generator for the recursive path. I guess adapted versions of something like https://cs.gmu.edu/~sean/papers/treecreation.pdf
yeah, more specifically you'd use with-gen
to attach a custom generator to the spec for ::expression
, and inside that use gen/fmap
to create sample expressions that would actually pass the spec
the advantage of fmap is it lets you use random generation while still respecting the generator state, so the seed for recreating the failure works
Interesting. Thanks @noisesmith. Let me go do some more reading π
When I boot up my repl, and eval my βmainβ namespace (what lein
could call core.clj
) Iβm getting FileNotFoundException
s on the other files in my project. If I eval those files then everything is fine. any ideas what I may be doing wrong? I think I have the files/namespace mapping correct
This project is using deps/clj, not lein
@ryan072 Are there any -
or _
in any of the filenames and/or namespaces?
-
in namespace, _
in files
(also, is this a project we can look at on GitHub?)
it is, but private
And when you say "eval my "main" namespace", what exactly do you mean? (require '[my-project.core])
yes, that
specifically, eval the (ns my-toplevel (:require [ β¦ ]))
If you're on macOS/Linux, could you share what tree .
displays when run inside your project, and also what that complete ns
form contains?
(it's hard to debug something we can't see π )
for sure
(ns yardstick.yardstick-jobs
(:gen-class)
(:require [mount.core :as mount]
[next.jdbc :as jdbc]
[yardstick.process-channel :as pc]
[yardstick.fetch-jobs :as fj]))
I donβt have tree
, which is weird because i remember using it in the past
(ns yardstick.channels
(:require [clojure.core.async :as async]))
^ one of the other fileβs namespace decWhat is the exact FNF exception you're seeing when you try to (require 'yardstick.yardstick-jobs)
in the REPL?
(or whatever it is you are typing into the REPL that throws an exception)
β¦ and now it works fine
whelp, sorry for wasting your time. I recreated the issue like 2x before posting here
and now everything is peachy
in general tho, if files match the directory structure under src
things should be fine, yes?
the actual rule is that the path to the namespace must match a file on classpath or a resource on classpath with a path matching the ns parts
src is a classpath root by default
makes sense
I find it somewhat surprising that require would give "file not found" as it can use files, or resources inside artifacts, (or even rare things like URLs...)
oh, it does say 'FileNotFoundException", wow
user=> (require 'aokldsjflas.asdfkjlasdf)
Execution error (FileNotFoundException) at user/eval290 (REPL:1).
Could not locate aokldsjflas/asdfkjlasdf__init.class, aokldsjflas/asdfkjlasdf.clj or aokldsjflas/asdfkjlasdf.cljc on classpath.
That is roughly what I saw
I'm trying to learn core.async and I'm having somewhat of a difficulty understanding what "parking" is and its implications. (I understand blocking). Could someone provide me a quick overview or some search terms that might help me?
Parking means that no thread is blocked and work stops until data is available
The arrival of data unparks the operation and it is queued to run again
When something is 'unparked', I assume it waits for the next available thread in the pool?
Yes
Which is why go blocks should never do blocking io (which can block a thread in that fixed size pool)
Thank you Alex